#-*- coding: utf-8 *-*
#===============================================================================
# Koro Business Environment
# Copyright (C) 2006,2008,2010  Antonio Corroppoli
#
#This file is part of Koro BE.
# 
# Koro BE is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# Koro BE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with Koro BE; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#===============================================================================

#controlli ridefiniti per comodita'
import string
import sys
import re
from decimal import Decimal
import wx.aui
#import wx.grid as gridlib
import wx.calendar
import  wx.lib.masked as  masked
#import wx.lib.agw.buttonpanel as bp
from koro.ui.wxgui.widgets import dialogs as di 
#import koro.ui.wxgui.dialogs as di
#import koro.gDateTime
#from koro.ui.wxgui import constants
from koro.ui.wxgui import util,images#,mellcfg
from koro.util import to_bool,euro,round
from wx.lib.mixins.listctrl import CheckListCtrlMixin,ListCtrlAutoWidthMixin

def _default_control_width():
    if 'linux' in sys.platform:
        return 250
    else:
        return 250#TODO: PRENDERE LE MISURE SU WIN...

def _default_control_height():
    if 'linux' in sys.platform:
        return 24
    else:
        return -1

DEFAULT_CONTROL_HEIGHT=_default_control_height()
DEFAULT_CONTROL_WIDTH=_default_control_width()
DEFAULT_SPACING=110#è la dimensione x della lable
DEFAULT_SIZE=(DEFAULT_CONTROL_WIDTH,DEFAULT_CONTROL_HEIGHT)

def _initial_size(size):
    if size[1]==-1:
        size=(size[0],DEFAULT_CONTROL_HEIGHT)
    if size[0]==-1:
        size=(DEFAULT_CONTROL_WIDTH,size[1])
    return size

_init_size=_initial_size    

VENDITA = 'V'
ACQUISTO = 'A'

#===============================================================================
# _ObjectViewer
#===============================================================================
class _ObjectViewer(object):
    def __init__(self,view,allow_null=False):
        self._default=''
        self._object=None
        self._attribute=view
        self._allow_null=allow_null
    
    def set_object(self,obj):
        self._object=obj
    
    def get_object(self):
        return self._object
    
    def get_view(self):
        return getattr(self._object,self._attribute,'')

    def set_view(self,view):
        self._attribute=view
    
    def load(self,objects):
        '''Carica gli elementi gestiti dal controllo. 
        Il parametro objects è una lista di wx.ItemContainer.'''
        self.clear()
        if self.is_null_allowed():
            self.append('---')
        for item in objects:
            self.append(getattr(item,self._attribute),item)
    
    def append(self,item,client_data=None):
        '''Override in subclass'''
        pass
    
    def clear(self):
        '''Override in subclass'''
        pass
    
    def is_null_allowed(self):
        return self._allow_null    


#===============================================================================
# _Viewer #Combobox e ListCtrl TODO:provare a eliminare
#===============================================================================
class _Viewer(object):
    def __init__(self,allow_null=False):
        self.allow_null=allow_null
        self.objects=None
    
    def load(self,objects):
        self.clear()
        if self.allow_null:
            self.Append('---')
        for item in objects:
            info=self._get_param(item)
            self.Append(*info)
    
    def clear(self):
        '''Override in subclass!'''
        raise Exception('Override in Subclass.')
    
    def _get_param(self,item):        
        '''Restituisce i dati da inserire e visualizzare nel controllo.
        Ad esempio per una ListBox restituisce una tupla con un elemento per ogni colonna;
        per una ComboBox una tupla (valore_da_visualizzare,client_data).
        
        Override in subclass!'''
        raise Exception('Override in Subclass.')
    
    def _get_attribute(self,item,attr):
        '''@param item: è un oggetto.
        @param attr: è un attributo dell'oggetto @item come stringa.(può essere un metodo)
        @return: il valore dell'attributo @item o il valore restituito da @item se è un metodo.
        '''  
        attribute=''        
        if isinstance(attr,basestring):
            attribute=getattr(item,attr)
        if isinstance(attr,tuple):
            attribute=item
            for a in attr:
                attribute=getattr(attribute,a)                
        if callable(attribute):
            return attribute()
        return attribute           
    

#------------------ COLORI STANDARD ---------------------#
mREAD_ONLY_COLOR     = (238,238,238,255)
mREQUIRED_COLOR      = (226,248,250)#(235,250,255,255)
mINVALID_VALUE_COLOR = (205,224,254,255)
mINVALID_BGCOLOR = (176,196,222)



#===============================================================================
# _HiddenData #usata da mTextCtrl
#===============================================================================
class _HiddenData(object):
    def __init__(self):
        self.__data = None

    def GetHiddenData(self):
        return self.__data

    def SetHiddenData(self,data):
        self.__data=data

    HiddenData=property(GetHiddenData,SetHiddenData)

####--------------- mHiddenCtrl -----------------#
#class mHiddenCtrl(object):
#    def __init__(self,name=None,value=None):
#        self.__value=value
#        self.__name=name
#
#    def GetName(self):
#        return self.__name
#
#    def GetValue(self):
#        return self.__value
#
#    def SetName(self,name):
#        self.__name=name
#
#    def SetValue(self,val):
#        self.__value=val

### Nuovi Controlli
KORO_NB_DEFAULT_STYLE=wx.aui.AUI_NB_DEFAULT_STYLE
KORO_NB_DEFAULT_STYLE &= ~(wx.aui.AUI_NB_CLOSE_BUTTON |
                           wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB |
                           wx.aui.AUI_NB_CLOSE_ON_ALL_TABS |
                           wx.aui.AUI_NB_TAB_MOVE)
                           
#===============================================================================
# KoroNotebook
#===============================================================================
class KoroNotebook(wx.aui.AuiNotebook):
    def __init__(self,parent,style=KORO_NB_DEFAULT_STYLE,*args,**kwargs):
        super(KoroNotebook,self).__init__(parent,style=style,*args,**kwargs)
        self.SetMinSize((400,350))


#class KoroAuiDockArt(wx.aui.AuiDefaultDockArt):
#    def __init__(self):
#        wx.aui.AuiDefaultDockArt.__init__(self)
#    
#    def DrawCaption(self, dc, window, text, rect, pane):
#        print 'dddddddd'
#        
#        b=wx.Brush()
#        b.SetColour(wx.Colour(A,A,A))
#        dc.SetBackGround(b)
#        wx.aui.AuiDefaultDockArt.DrawCaption(self,dc, window, text, rect, pane)
        

#===============================================================================
# KoroPageManager
#===============================================================================
class KoroPageManager(wx.aui.AuiManager):
    def __init__(self,managed_window,*args,**kwargs):
        super(KoroPageManager,self).__init__(*args,**kwargs)
        #self.SetArtProvider(KoroAuiDockArt())
        self.SetManagedWindow(managed_window)
        self.Update()
        self.__page=None
    
    def close_center_pane(self):
        if self.__page is None:
            return
        self.__page.before_close()
        self.ClosePane(self.GetPane(self.__page.TITLE))
        del self.__page
        self.__page=None
    
    def show_center_pane(self,page,parent,context,objects,*args,**kwargs):
        if self.__page is not None:
            self.close_center_pane()
        page=page(parent,context,objects,*args,**kwargs)
        self.AddPane(page, wx.aui.AuiPaneInfo().
                              Name(page.TITLE).
                              CenterPane().
                              DestroyOnClose().
                              Caption(page.TITLE).
                              CaptionVisible().
                              CloseButton(False))
        self.GetPane(page.TITLE).Show(True)
        self.Update()
        self.__page=page
        self.__page.show()
    
    def get_center_pane(self):
        return self.__page
    
    def is_center_pane(self,name):
        if self.__page is None:
            return False
        return self.__page.TITLE==name
    
    def un_init(self):
        self.close_center_pane()
        del self.__page
        self.UnInit()
        

##===============================================================================
## ModuleCheckBox
##===============================================================================
#class ModuleCheckBox(wx.CheckBox):
#    def __init__(self,parent,name,enabled,*args,**kwargs):
#        wx.CheckBox.__init__(self,parent,*args,**kwargs)       
#        self.SetValue(enabled)
#        self.SetLabel(name)
#    
#    def get_name(self):
#        return self.GetLabelText()
#    
#    def is_selected(self):
#        return self.GetValue()

kLC_DEFAULT_STYLE=wx.VSCROLL|wx.HSCROLL|wx.SUNKEN_BORDER|wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_HRULES|wx.LC_VRULES
#===============================================================================
# KoroListCtrl
#===============================================================================
class KoroListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin):
    def __init__(self, parent, ID=wx.NewId(), pos=wx.DefaultPosition,
                 size=wx.DefaultSize, edit=False, style=kLC_DEFAULT_STYLE):
        if edit:
            style=style|wx.LC_EDIT_LABELS
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
        ListCtrlAutoWidthMixin.__init__(self)
        
        
#===============================================================================
# CheckListCtrl
#===============================================================================
class CheckListCtrl(KoroListCtrl, CheckListCtrlMixin):
    def __init__(self, parent,*args,**kwargs):
        KoroListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES)
        CheckListCtrlMixin.__init__(self)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
        self._checked=[]

    def OnItemActivated(self, evt):
        self.ToggleItem(evt.m_itemIndex)

    # this is called by the base class when an item is checked/unchecked
    def OnCheckItem(self, index, flag):
        nome = self.GetItemText(index)        
        if flag:
            self._checked.append(nome)
        else:
            self._checked.remove(nome)
    
    def get_checked(self):
        return tuple(self._checked)



#===============================================================================
# KoroControl
#===============================================================================
class KoroControl(wx.BoxSizer):
    def __init__(self,label,control,spacing=110,style=wx.HORIZONTAL):
        '''Rappresenta un control base.Il parametro spacing rappresenta la lunghezza della lable.'''
        self._spacing=spacing#spazio tra la label e il control
        self.control=control
        self.label=wx.StaticText(control.Parent,label=label)
        orientation=wx.HORIZONTAL & style or wx.VERTICAL & style or wx.HORIZONTAL
        if orientation==wx.HORIZONTAL:
            self.label.SetInitialSize((spacing,-1))
        wx.BoxSizer.__init__(self,orientation)
        self.__do_layout()
    
    def set_accelerator_table(self,*args,**kwargs):
        self.control.SetAcceleratorTable(wx.AcceleratorTable(*args,**kwargs))
    
    def __do_layout(self):
        self.Add(self.label,0,wx.ALIGN_CENTER_VERTICAL)
        self.Add(self.control,0)
        self.Layout()
    
    def clear(self):
        self.control.clear() 
    
    def hide(self):
        super(KoroControl,self).ShowItems(False)

    def show(self,show=True):
        super(KoroControl,self).ShowItems(show)
      
    def enable(self,enable=True):
        self.control.Enable(enable)
    
    def get_value(self):
        return self.control.get_value()
    
    def get_selection(self):
        self.control.get_selection()
    
    def get_string_selection(self):
        return self.control.get_string_selection()
    
    def set_value(self,value):
        self.control.set_value(value)
    
    def set_selection(self,sel):
        self.control.set_selection(sel)
    
    def set_string_selection(self,sel):
        self.control.set_string_selection(sel)
    
    def get_id(self):
        return self.control.GetId()
    
    def append(self,item,client_data=None):
        return self.control.append(item,client_data)
    
    def get_client_data(self,sel=-1):
        return self.control.get_client_data(sel)
    
    def get_selected_object(self):
        return self.control.get_object()
    
    def set_initial_size(self,size=wx.DefaultSize):
        self.control.SetInitialSize(size)
    
    def bind(self,*args,**kwargs):
        return self.control.Bind(*args,**kwargs)
    
    def set_label(self,label):
        self.label.SetLabel(label)
    
    def set_focus(self):
        self.control.SetFocus()
    
    def change_value(self,value):
        self.control.change_value(value)


##===============================================================================
## LabelCtrl
##===============================================================================
#class LabelCtrl(KoroControl):
#    def __init__(self,*args,**kwargs):
#        lb=kwargs.pop('label','')
#        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
#        KoroControl.__init__(self, lb, wx.StaticText(*args,**kwargs), orientation)
#        
#    def clear(self):
#        self.control.SetLabel('')
#      
##    def enable(self,enable=True):
##        self.control.Enable(enable)
#    
#    def get_value(self):
#        return self.control.GetLabel()
#    
#    def set_value(self,value):
#        self.control.SetLabel(value)


#===============================================================================
# Wrapper Class per wxComboBox #usato in magazzino...e da LabelComboBox
#===============================================================================
class ComboBox(wx.ComboBox,_Viewer):
    '''Deprecato rimpiazzato da _ComboBox'''
    def __init__(self,*args,**kwargs):
        info=kwargs.pop('item_info',None)
        allow_null=kwargs.pop('allow_null',False)
        size=kwargs.pop('size',(-1,-1))
        size=_initial_size(size)
        super(ComboBox,self).__init__(size=size,*args,**kwargs)
        _Viewer.__init__(self,allow_null)
        if isinstance(info,basestring):
            self.attr=info
        if isinstance(info,_Viewer):
            self.attr=info.attr
    
    def clear(self):
        return self.Clear()
    
    def _get_param(self,item):
        '''Restituisce una tupla (valore_da_visualizzare,oggetto).'''        
        param=(self._get_attribute(item, self.attr),item)
        return param
    
    def set_value(self,val):
        if self.FindString(val)!=wx.NOT_FOUND:
            self.SetStringSelection(val)
        else:
            self.SetValue(val)
    
    def get_value(self):
        return self.GetValue()
    
    def get_selected_object(self):
        return self.GetClientData(self.GetSelection())
    
    def load_items(self,items):
        self.Clear()
        return self.AppendItems(items)

#===============================================================================
# Wrapper Class per wxComboBox
#===============================================================================
class _ComboBox(wx.ComboBox):
    def __init__(self,*args,**kwargs):
        kwargs['size']=_initial_size(kwargs.pop('size',(-1,-1)))
        super(_ComboBox,self).__init__(*args,**kwargs)
    
    def clear(self):
        return self.Clear()
    
    def set_value(self,val):
        if self.FindString(val)!=wx.NOT_FOUND:
            self.SetStringSelection(val)
        else:
            self.SetValue(val)
    
    def get_value(self):
        return self.GetValue()
    
    def get_selected_object(self):
        return self.GetClientData(self.GetSelection())
    
    def set_string_selection(self,string):
        self.SetStringSelection()
    
    def get_string_selection(self):
        return self.GetStringSelection()
    
    def append(self,item,client_data=None):
        self.Append(item, client_data)
    
    def load_items(self,items):
        self.Clear()
        return self.AppendItems(items)


#===============================================================================
# LabelComboBox
#===============================================================================
class LabelComboBox(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING) 
        cb=ComboBox(*args,**kwargs)
        KoroControl.__init__(self,lb,cb,spacing,orientation)
    
#    def get_selected_object(self):
#        return self.control.get_selected_object()
    
    def load_items(self,*args,**kwargs):
        self.control.load_items(*args,**kwargs)
    
    def load(self,objects):
        self.control.load(objects)


#===============================================================================
# LabelChoice
#===============================================================================
class LabelChoice(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING)
        choice=KoroChoice(*args,**kwargs)
        KoroControl.__init__(self,lb,choice,spacing,orientation)


#===============================================================================
# LabelTextCtrl
#===============================================================================
class LabelTextCtrl(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        valuta=kwargs.pop('valuta',False)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING)
        ontext = kwargs.pop('ontext',None)
        text=None
        if valuta:
            text=ValutaCtrl(*args,**kwargs)
        else:
            text=mTextCtrl(*args,**kwargs)
            if ontext is not None:
                text.Bind(wx.EVT_TEXT, ontext)
        KoroControl.__init__(self,lb,text,spacing,orientation)
    
    def clear(self):
        self.control.Clear() 
      
#    def enable(self,enable=True):
#        self.control.Enable(enable)
    
    def get_value(self):
        return self.control.GetValue()
    
    def set_value(self,value):
        self.control.SetValue(value)


#===============================================================================
# LabelDateCtrl
#===============================================================================
class LabelDateCtrl(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING)
        dpc = wx.DatePickerCtrl(size=(120,25),
                                style = wx.DP_DROPDOWN
                                      | wx.DP_SHOWCENTURY
                                      | wx.DP_ALLOWNONE,*args,**kwargs )
        KoroControl.__init__(self,lb,dpc,spacing,orientation)
    
    def get_value(self):
        return util.to_pydate(self.control.GetValue())
    
    def set_value(self,value):
        self.control.SetValue(util.to_wxdate(value))

### Fine Nuovi Controlli
        

EVT_PICKER=wx.EVT_BUTTON
class CompositeCtrl(wx.BoxSizer):
    def __init__(self,ctrl,id=-1,label='',lbsize=(115,-1),picker=False,label_style=wx.FONTWEIGHT_NORMAL,*args,**kwargs):
        wx.BoxSizer.__init__(self)        
        if lbsize!=(0,0):
            label=wx.StaticText(ctrl.GetParent(),wx.NewId(),label,size=lbsize)#(105,17))
            font=label.GetFont()
            font.SetWeight(label_style)
            label.SetFont(font)        
            #sizerBorder=(ctrl.GetSize().GetHeight() - label.GetSize().GetHeight())/2
            self.Add(label,0,wx.ALIGN_CENTER_VERTICAL)
        self.Add(ctrl,0,wx.ALIGN_RIGHT)
        if 'ctrl_1' in kwargs:#lasciato per compatibilita. da rimuovere
            self.Add(kwargs['ctrl_1'])#,0,wx.ALIGN_RIGHT)
        if 'ctrls' in kwargs:
            self._add_controls(kwargs['ctrls'])
        if picker:
            #h,w=ctrl.GetSizeTuple()
            x=y=ctrl.GetSize().y-2
            picker=wx.Button(ctrl.GetParent(),id,'...',size=(x,y))
            #ctrl.Parent.Bind(wx.EVT_BUTTON,self.onPicker,id=id)
            self.Add(picker,0,wx.ALIGN_CENTER)
        
        
    def _add_controls(self,controls):
        for ctrl in controls:
            self.Add(ctrl)

    def onPicker(self,event):
        print 'picker catturato'
        event.Skip(True)


#===============================================================================
# TextPickerCtrl
#===============================================================================
class TextPickerCtrl(wx.BoxSizer):
    def __init__(self,parent,id,size):        
        wx.BoxSizer.__init__(self)
        #mainsizer=wx.BoxSizer()
        text_ctrl=wx.TextCtrl(parent,size=(50,-1))
        picker_ctrl=wx.Button(parent,id,size=(22,text_ctrl.GetSize().y-3),label='...')
        #self.SetTextCtrl(text_ctrl)        
        #self.SetPickerCtrl(picker_ctrl)
        self.Add(text_ctrl,1)
        self.Add(picker_ctrl,0)        
        #self.SetSizer(mainsizer)
        #self.SetSizeWH(text_ctrl.GetSize().x+23,text_ctrl.GetSize().y+1)
        #mainsizer.Layout()
        self.Layout()

###--------------- mPopupComboCtrl -----------------#
##class mPopupComboCtrl(wx.Window):
##    def __init__(self,parent,id=-1,label=''):
##        wx.Window.__init__(self,parent)
##        topsizer=wx.BoxSizer()
##        txt=wx.TextCtrl(self,size=(245,-1))
##        txt.SetEditable(False)
##        topsizer.Add(CompositeCtrl(txt,label=label,picker=True))
##        h,w=txt.GetSizeTuple()
##        self.SetSize((h+w+105,w))
##        self.SetSizer(topsizer)
##        self.Bind(wx.EVT_BUTTON,self.onPicker)
##
##    def onPicker(self,evt):
##        evt.Skip(False)
##        print 'popup picker'
        
        
#===============================================================================
# KoroChoice
#===============================================================================
class KoroChoice(wx.Choice):
    def __init__(self,*args,**kwargs):
        kwargs['size']=_initial_size(kwargs.pop('size',(-1,-1)))
        wx.Choice.__init__(self,*args,**kwargs)

#    def get_value(self):
#        return self.GetStringSelection()
#
#    def set_value(self,val):
#        self.SetStringSelection(val)
    
    def set_string_selection(self,val):
        self.SetStringSelection(str(val))
    
    def get_string_selection(self):
        return self.GetStringSelection()
    
    def append(self,item,client_data=None):
        return self.Append(item,client_data)
    
    def set_selection(self,sel):
        return self.SetSelection(sel)
    
    def get_client_data(self,sel=-1):
        if sel==-1:
            sel=self.GetSelection()
        return self.GetClientData(sel)
    
    def get_selected_object(self):
        return self.GetClientData(self.GetSelection())
    
    value=property(get_string_selection,set_string_selection)
    object=property(get_client_data)


#===============================================================================
# ObjectChoice
#===============================================================================
class ObjectChoice(KoroChoice,_ObjectViewer):
    def __init__(self,*args,**kwargs):
        view=kwargs.pop('view')
        allow_null=kwargs.pop('allow_null',False)
        KoroChoice.__init__(self,*args,**kwargs)
        _ObjectViewer.__init__(self,view,allow_null)
    
    def clear(self):
        self.Clear()
    
    def set_value(self,obj):
        self.set_object(obj)
        if obj is None and self.is_null_allowed():
            self.set_selection(0)
        else:
            self.set_string_selection(self.get_view())
    

#===============================================================================
# ObjectComboBox
#===============================================================================
class ObjectComboBox(_ComboBox,_ObjectViewer):
    def __init__(self,*args,**kwargs):
        view=kwargs.pop('view')
        allow_null=kwargs.pop('allow_null',False)
        _ComboBox.__init__(self,*args,**kwargs)
        _ObjectViewer.__init__(self,view,allow_null)


#===============================================================================
# LabelObjectComboBox
#===============================================================================
class LabelObjectComboBox(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING) 
        cb=ObjectComboBox(*args,**kwargs)
        KoroControl.__init__(self,lb,cb,spacing,orientation)
    
    def load_items(self,*args,**kwargs):
        self.control.load_items(*args,**kwargs)
    
    def load(self,objects):
        self.control.load(objects)


#===============================================================================
# LabelObjectChoice
#===============================================================================
class LabelObjectChoice(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING)
        choice=ObjectChoice(*args,**kwargs)
        KoroControl.__init__(self,lb,choice,spacing,orientation)
    
    def load(self,objects):
        self.control.load(objects)
        self.control.set_selection(0)
    
    def GetId(self):
        return self.control.GetId()
    
    def Bind(self,*args,**kwargs):
        return self.control.Bind(*args,**kwargs)
    
    def get_selected_object(self):
        return self.control.get_selected_object()
    
    def clear(self):
        self.control.clear()
    
    def is_null_allowed(self):
        return self.control.is_null_allowed()
        

#--------------- mTextCtrl & Validator -----------------#            

mTE_DEFAULT_BGCOLOR = (255, 255, 255, 255)

mTE_READ_ONLY = 2
mTE_REQUIRED  = 4
mTE_ALPHA_ONLY = 8
mTE_DIGIT_ONLY = 16
mTE_MASK_CODE  = 32
mTE_EVT_ONKEY = 64 #per i codici a lunghezza variabile
mTE_TITLED = 128
mTE_UPPER = 256
mTE_ZFILL = 512 #il valore ha sempre len=maxlen;gli spazi vengono riempiti da zeri
mTE_DEFAULT_STYLE   = 1
class mTextCtrl(wx.TextCtrl,_HiddenData):
    def __init__(self,*args,**kwargs):
        size=kwargs.pop('size',(-1,-1))
        style=kwargs.pop('style',0)
        size=_initial_size(size)
#        if style & wx.TE_MULTILINE:
#            size=(size[0],-1)
        kwargs['style']=style
        bgcolor = kwargs.pop('bgcolor',mTE_DEFAULT_BGCOLOR)
        mstyle  = kwargs.pop('mstyle',mTE_DEFAULT_STYLE)
        maxlen  = kwargs.pop('maxlen',0)
        wx.TextCtrl.__init__(self,size=size,*args,**kwargs)
        _HiddenData.__init__(self)
        self._bgcolor = bgcolor
        self._mstyle = mstyle
        self._maxlen=maxlen
        self.Bind(wx.EVT_CHAR,self.OnChar)
        self.Bind(wx.EVT_TEXT,self.OnText)
        self.Bind(wx.EVT_KILL_FOCUS,self.OnKillFocus)
        self.SetMaxLength(maxlen)
        self.SetMellStyle(mstyle)

    def OnChar(self,evt):
        key=evt.GetKeyCode()
        tc=evt.GetEventObject()
        if (key==wx.WXK_RETURN) and not evt.ShiftDown():
            self.Navigate()
            evt.Skip()
            return
        if (key==wx.WXK_RETURN) and evt.ShiftDown():
            self.Navigate(wx.NavigationKeyEvent.IsBackward)
            evt.Skip()
            return
        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
            evt.Skip()
            return
        if chr(key) in string.letters and self._mstyle & mTE_UPPER:
            tc.AppendText(chr(key).upper())                          
            return            
        
        evt.Skip()
        
    def OnText(self,evt):
#        text=evt.GetString()
#        tc=evt.GetEventObject()
#        sel=tc.GetSelection()
#        if self._mstyle & mTE_TITLED:
#            tc.ChangeValue(text.title())
#            tc.SetSelection(*sel)
        if self.IsValid():
            self.SetBackgroundColour(self._bgcolor)
        else:
            self.SetBackgroundColour(mINVALID_BGCOLOR)
        self.Refresh()
        evt.Skip()

    def OnKillFocus(self,evt):
#        if self._mstyle & mTE_UPPER:
#            wx.TextCtrl.SetValue(self,wx.TextCtrl.GetValue(self).upper())
#        if self._mstyle & mTE_TITLED:
#            wx.TextCtrl.SetValue(self,wx.TextCtrl.GetValue(self).title())
        evt.Skip()

    def SetMellStyle(self,mstyle):
        assert not(mstyle & mTE_ALPHA_ONLY and mstyle & mTE_DIGIT_ONLY)
        assert not(mstyle & mTE_READ_ONLY and mstyle > mTE_READ_ONLY)
        self.SetEditable(True)
        if mstyle & mTE_DEFAULT_STYLE:
            self._bgcolor = mTE_DEFAULT_BGCOLOR
##            self.SetBackgroundColour(self._bgcolor)
##            self.Refresh()
            self._mstyle = mstyle = mTE_DEFAULT_STYLE
#            return
        
        if mstyle & mTE_READ_ONLY:
            self._bgcolor = mREAD_ONLY_COLOR
            self.SetEditable(False)
        elif mstyle & mTE_REQUIRED:
            self.SetEditable(True)
            self._bgcolor = mREQUIRED_COLOR
        if mstyle & mTE_REQUIRED or \
           mstyle & mTE_DIGIT_ONLY or \
           mstyle & mTE_ALPHA_ONLY:
            self.SetValidator(mValidator())
        self.SetBackgroundColour(self._bgcolor)
        self.Refresh()

    def GetMellStyle(self):
        return self._mstyle
    
    def RestoreBgcolor(self):
        self.SetBackgroundColour(self._bgcolor)
        self.Refresh()

    def SetValue_OLD(self,val):
        print 'mTextCtrl.SetValue'
        filler=self._maxlen - len(val)
        if self._mstyle & mTE_EVT_ONKEY and \
           filler > 0:
            val = '0'*filler+val
        wx.TextCtrl.SetValue(self,val)

    def SetValue(self,val):
        print 'mTextCtrl.SetValue'
        #filler=self._maxlen - len(val)
        if self._mstyle & mTE_ZFILL:
            val = val.zfill(self._maxlen)
        wx.TextCtrl.SetValue(self,str(val))

    def IsValid(self,val=None):
        print 'mTextCtrl.IsValid'
        print self.GetName()
        if val is None:
            val=self.GetValue()
        if val=="" or \
           not self._mstyle & mTE_ZFILL or \
           len(val) == self._maxlen:
            return True
        return False

    def IsValid_old(self,val=None):        
        if val is None:
            val=self.GetValue()
        if not val or \
           not self._mstyle & mTE_EVT_ONKEY or \
           len(val) == self._maxlen:
            return True
        return False            

    def SetValue_deprecated(self,val,p='2'):
        ip=self.GetInsertionPoint()
        if self._mstyle & mTE_MASK_CODE:
            val=val.replace('-','')
            val=re.sub(r'(?<=\A(\w|\s){'+p+'})','-',val)
            if ip==2:ip+=1
        wx.TextCtrl.SetValue(self,val)
        self.SetInsertionPoint(ip)    

    def GetValue_deprecated(self):
        val = wx.TextCtrl.GetValue(self)
        if self._mstyle & mTE_MASK_CODE:
            val.replace('-','')
        return val


#===============================================================================
# ValutaCtrl
#===============================================================================
class ValutaCtrl(mTextCtrl):
    def __init__(self,*args,**kwargs):
        mTextCtrl.__init__(self,*args,**kwargs)
        self._value='0.00'
        self.Clear()
        self.Bind(wx.EVT_CHAR,self.on_char)
        self.Bind(wx.EVT_TEXT,self.on_text)
        self.Bind(wx.EVT_KILL_FOCUS,self.on_kill_focus)
        self.Bind(wx.EVT_SET_FOCUS, self.on_set_focus)
    
    def __fmt(self):
        return '{0} €'.format(self._value)
    
    def SetValue(self,value):
        self._value=str(value)
        self.ChangeValue(self.__fmt())
    
    def GetValue(self):
        return self._value

    def on_char(self,evt):
        print 'ValutaCtrl on_char'
        key=evt.GetKeyCode()
        tc=evt.GetEventObject()
        if (key==wx.WXK_RETURN) and not evt.ShiftDown():
            self.Navigate()
            evt.Skip()
            return
        if (key==wx.WXK_RETURN) and evt.ShiftDown():
            self.Navigate(wx.NavigationKeyEvent.IsBackward)
            evt.Skip()
            return
        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
            evt.Skip()
            return
        if chr(key) not in string.digits and chr(key) !=',':
            evt.Skip(False)                          
            return            
        
        evt.Skip()
        
    def on_text(self,evt):
        print 'ValutaCtrl on_text'
#        text=evt.GetString()
#        tc=evt.GetEventObject()
#        sel=tc.GetSelection()
#        if self._mstyle & mTE_TITLED:
#            tc.ChangeValue(text.title())
#            tc.SetSelection(*sel)
        print self.GetValue()
        evt.Skip()

    def on_kill_focus(self,evt):
        print 'ValutaCtrl on_kill_focus'
#        if self._mstyle & mTE_UPPER:
#            wx.TextCtrl.SetValue(self,wx.TextCtrl.GetValue(self).upper())
#        if self._mstyle & mTE_TITLED:
#            wx.TextCtrl.SetValue(self,wx.TextCtrl.GetValue(self).title())
        self._value=super(ValutaCtrl,self).GetValue()
        self.ChangeValue(self.__fmt())
        evt.Skip()
    
    def on_set_focus(self,evt):
        print 'ValutaCtrl on_set_focus'
        self.ChangeValue(self._value)
        evt.Skip(True)
    
#    def SetValue(self,value):
##        self.HiddenData=value
##        mTextCtrl.SetValue(self,util.euro(value))
#    
#    def GetValue(self):
#        return self.HiddenData
    
    def Clear(self):
        self.SetValue('0.00')


#===============================================================================
# mValidator
#===============================================================================
class mValidator(wx.PyValidator):
    def __init__(self):
        """ Standard constructor.
        """
        wx.PyValidator.__init__(self)
        #print "costruttore mValidator"
        self.Bind(wx.EVT_CHAR,self.OnChar)

    def OnChar(self, evt):
        print 'mValidator.OnChar'
        key = evt.GetKeyCode()
        tc=evt.GetEventObject()
        val = tc.GetValue()
        style=tc.GetMellStyle()

##        if style & mTE_MASK_CODE and key == 127:
##            print 'canc'
##            return

        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
            evt.Skip()
            return
        
        if style & mTE_ALPHA_ONLY:
            if not chr(key) in string.letters: return

        if style & mTE_DIGIT_ONLY:
            if not chr(key) in string.digits: return

        if style & mTE_MASK_CODE:#togliere
            ip=tc.GetInsertionPoint()
            if ip < 2 and ip != len(val):
                #print len(val), tc.GetLastPosition()
                val = val.replace('-','')
                val = val[0:ip]+val[(ip+1):]
                print val
                tc.SetValue(val,'1')
            else:
                tc.SetValue(val)
        #il colore cambia in caso di fallimento di Validate()
        #ripristino il colore originale
        #tc.RestoreBgcolor()
##        if tc._maxlen and \
##           style & mTE_EVT_ONKEY and \
##           len(val) == tc._maxlen - 1:
##            tc.AppendText(chr(key))                
        evt.Skip()
        return            

    def Clone(self):
        print 'mValidator.Clone'
        return mValidator()

    def Validate(self,win):
        tc = self.GetWindow()
        print 'mValidator.Validate'
        val = tc.GetValue()

        style = tc.GetMellStyle()
        if style & mTE_REQUIRED:
            #print 'richiesto'
            if not to_bool(val):
                print 'validator fail'
                msgbox = di.mPopupMsg(win,di.mMSG_REQUIRED,tc.GetScreenPositionTuple())                                
                #tc.SetBackgroundColour(mINVALID_VALUE_COLOR)
                #tc.SetFocus()
                #tc.Refresh()
                msgbox.Show()
                return False
        return True


    def TransferToWindow(self):
        """ Transfer data from validator to window.

             The default implementation returns False, indicating that an error
             occurred.  We simply return True, as we don't do any data transfer.
        """
        return True # Prevent wxDialog from complaining.


    def TransferFromWindow(self):
        """ Transfer data from window to validator.

             The default implementation returns False, indicating that an error
             occurred.  We simply return True, as we don't do any data transfer.
        """
        return True # Prevent wxDialog from complaining.


LC_DEFAULT_CONTROL = 1 
#===============================================================================
# LabeledCtrl TODO:eliminare:usato in tutte le classi opzioni.
#===============================================================================
class LabeledCtrl(wx.BoxSizer):
    def __init__(self,parent,id=-1,*args,**kwargs):
        control=kwargs.pop('control',LC_DEFAULT_CONTROL)
        label=kwargs.pop('label','')
        label_size=kwargs.pop('label_size',(105,-1))
        #maxlen=kwargs.pop('maxlen',0)
        self.picker_func=kwargs.pop('picker_func',None)
        wx.BoxSizer.__init__(self,wx.HORIZONTAL)
        self.__picker=None
        self.__label=wx.StaticText(parent,wx.NewId(),label,size=label_size)#(105,17))
        if control == LC_DEFAULT_CONTROL:
            control=mTextCtrl(parent=parent,*args,**kwargs)
        assert isinstance(control,wx.Control),Exception('LabeledCtrl: Atteso wx.Control.')
        self.__ctrl=control
        #sizer_border=(self.__ctrl.GetSize().GetHeight() - self.__label.GetSize().GetHeight())/2
        self.Add(self.__label,0,wx.ALIGN_CENTER_VERTICAL)
        self.Add(self.__ctrl,0,wx.ALIGN_RIGHT)
        if self.picker_func is not None:
            self.__add_picker_ctrl()
        self.Layout()

    def __add_picker_ctrl(self):
        if self.__picker is not None:
            return
        width=self.__ctrl.GetSize().width
        self.__picker=wx.Button(self.__ctrl.Parent,wx.ID_ANY,'...',size=(width,width))
        self.__ctrl.Parent.Bind(wx.EVT_BUTTON,self._on_picker,id=self.__picker.GetId())
        self.Add(self.__picker)
     
    def set_picker_func(self,func):
        self.picker_func=func

    def _on_picker(self,event):
        print 'onpicker'
        event.Skip(True)
        self.picker_func(event)

    def hide(self):
        super(LabeledCtrl,self).ShowItems(False)

    def show(self,show=True):
        super(LabeledCtrl,self).ShowItems(show)

    def enable(self,enable=True):
        self.__ctrl.Enable(enable)

    def set_value(self,value):
        self.__ctrl.SetValue(value)

    def get_value(self):
        return self.__ctrl.GetValue()  
    
    def clear(self):
        self.__ctrl.Clear()


##--------------- mLabelTextCtrl -----------------#
##mLT_DEFAULT_STYLE = 1
##mLT_USE_PICKER = 512 
#class mLabelTextCtrl(wx.Window):
#    def __init__(self,parent,id=-1,size=(240,-1),label='',lbsize=(105,-1),maxlen=0,picker=False,*args,**kwargs):
#        wx.Window.__init__(self,parent)
#        self.__label=wx.StaticText(self,wx.NewId(),label,size=lbsize)#(105,17))
#        
#        self.__txtCtrl=mTextCtrl(parent=self,id=-1,size=size,*args,**kwargs)
#        sizerBorder=(self.__txtCtrl.GetSize().GetHeight() - self.__label.GetSize().GetHeight())/2
#        s=wx.BoxSizer()
#        s.Add(self.__label,0,wx.TOP|wx.BOTTOM|wx.RIGHT|wx.LEFT,sizerBorder)
#        s.Add(self.__txtCtrl,0,wx.ALIGN_RIGHT)
#        if picker:
#            h,w=self.__txtCtrl.GetSizeTuple()
#            self.__picker=wx.Button(self,id,'...',size=(w,w))
#            parent.Bind(wx.EVT_BUTTON,self.onPicker,id=id)
#            s.Add(self.__picker)
#        self.SetSizer(s)
#        self.Layout()
#
#    def onPicker(self,event):
#        event.Skip(True)



##------------------------------ mPickerCtrl deprecato: usare mLabelTextCtrl------------------------------#
#mPI_DEFAULT_STYLE = 1
#mPI_EDITABLE    = 2            
#class mPickerCtrl__OLD(wx.TextCtrl,_HiddenData):
#    def __init__(self,id,evtfunc,mstyle=mPI_DEFAULT_STYLE,maxlen=0,*args,**kwargs):
#        kwargs['id']=wx.NewId()
#        wx.TextCtrl.__init__(self,*args,**kwargs)
#        _HiddenData.__init__(self)
#        self.SetMaxLength(maxlen)
#        if mstyle & mPI_DEFAULT_STYLE:
#            self.SetEditable(False)
#            self.SetBackgroundColour(mREAD_ONLY_COLOR)
#            self.Refresh()    
#        x,y = self.GetSizeTuple()
#        s=wx.BoxSizer()
#        s.Add((x+(y+1),10))
#        self.Bind(wx.EVT_LEFT_DCLICK,evtfunc,id=kwargs['id'])
###        from debug import DEBUG
###        DEBUG()
###        self.b=but
###        print self.b.Reparent(self)
#        
#        
#        #print 'porca troia'
#        self.b=wx.Button(id=id,parent=kwargs['parent'],size=(y-2,y-2),style=wx.NO_BORDER | wx.NO_3D)
#        s.Add(self.b,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.FIXED_MINSIZE)
###        self.b=wx.BitmapButton(self)
#        self.Bind(wx.EVT_BUTTON,evtfunc,id=id)
#        
#        
#        
#        self.SetSizer(s)
#        self.Layout()


##---------------------Nuova classe mPickerCtrl  2/12/08 deprecato il 5/12/08 ------------------------------#
#mPI_DEFAULT_STYLE = 1
#mPI_EDITABLE    = 2            
#class mPickerCtrl(wx.Control,_HiddenData):
#    def __init__(self,id,evtfunc,mstyle=mPI_DEFAULT_STYLE,maxlen=0,value='',*args,**kwargs):
#        kwargs['id']=wx.NewId()
#        wx.Control.__init__(self,kwargs['parent'])#,*args,**kwargs)
#        _HiddenData.__init__(self)
#        
#        
#        self.__txtCtrl=wx.TextCtrl(self,size=kwargs['size'])
#        x,y = self.__txtCtrl.GetSizeTuple()
#        self.__btn=wx.Button(id=id,parent=self,size=(y-2,y-2),label='..',style=wx.NO_BORDER | wx.NO_3D)
#        self.__txtCtrl.SetMaxLength(maxlen)
#        if mstyle & mPI_DEFAULT_STYLE:
#            self.__txtCtrl.SetEditable(False)
#            self.__txtCtrl.SetBackgroundColour(mREAD_ONLY_COLOR)
#            self.__txtCtrl.Refresh()    
#        
#        s=wx.BoxSizer()
###        s.Add(self.__btn)#,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.FIXED_MINSIZE)
#
#        s.Add(self.__txtCtrl)#,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.FIXED_MINSIZE)
#        self.Bind(wx.EVT_LEFT_DCLICK,evtfunc,id=kwargs['id'])
###        from debug import DEBUG
###        DEBUG()
###        self.b=but
###        print self.b.Reparent(self)
#        
#        
#        #print 'porca troia'
#        
#        s.Add(self.__btn,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.FIXED_MINSIZE)
#        self.Bind(wx.EVT_BUTTON,evtfunc,id=id)    
#        self.SetSizer(s)
#        self.Layout()
#        
        
#===============================================================================
# ViewInfo
#===============================================================================
class ViewInfo(object):
    '''Informazioni di visualizzazione. Usato da ListCtrl e ComboBox.'''    
    def __init__(self,*args,**kwargs):
        '''    
        Parametri validi:
            heading: intestazione colonna (ListCtrl)
            width: larghezza colonna (ListCtrl)
            attr: stringa o tupla degli attributi da visualizzare (ComboBox,ListCtrl).
        
        Se invocato con un parametro, questo viene inteso come 'attr'.
        Se invocato con tre parametri, vengono interpretati come (heading,width,attr).            
        '''
        if len(args)>0:
            self._set_args(*args)
        if len(kwargs)>0:
            self._set_kwargs(**kwargs)
    
    def _set_args(self,*args):
        if len(args)==1:
            setattr(self,'attr',args[0])            
        elif len(args)==3:
            setattr(self,'heading',args[0])
            setattr(self,'width',args[1])
            setattr(self,'attr',args[2])
            setattr(self,'format',wx.LIST_FORMAT_LEFT)
        elif len(args)==4:
            setattr(self,'heading',args[0])
            setattr(self,'width',args[1])
            setattr(self,'attr',args[2])
            setattr(self,'format',args[3])
        else:
            raise Exception('ViewInfo_set_args: {0}: Numero argomenti errato.'.format(len(args)))
    
    def _set_kwargs(self,**kwargs):
        for kw in kwargs:
            setattr(self,kw,kwargs[kw]) 
            
Column=ViewInfo#alias per ListCtrl
Item=ViewInfo#alias per Combobox

  
#===============================================================================
# KoroListCtrlManager
#===============================================================================
class KoroListCtrlManager(object):
    def __init__(self):
        self._objects=None#dizionario {indice_in_lista:oggetto}
        self._list=None
        self._columns_info=None
        self._previous_item=-1
        self._current_item=-1
        self._old_item=-1#non usato
        self._callback={}
        self._selected_callback=None
    
    def bind_callback(self,event,callback):
        if event in self._callback:
            return
        if event!=wx.EVT_LIST_ITEM_SELECTED:#questo evento è sempre legato
            self._list.Bind(event,self._event_handler)
        self._callback[event]=callback
    
    def unbind_callback(self,event):
        if event not in self._callback:
            return
        if event!=wx.EVT_LIST_ITEM_SELECTED:#questo evento è sempre legato
            self._list.Unbind(event)
        del self._callback[event]
    
    def clear_callback(self):
        for evt in self._callback:
            if evt!=wx.EVT_LIST_ITEM_SELECTED:
                self._list.Unbind(evt)
        del self._callback
        self._callback={}
    
    def set_focus(self):
        self._list.SetFocus()
    
    def get_managed_list(self):
        return self._list
    
    def add_object(self,item_object):
        item_info=self._get_param(item_object)
        index=self.add_item(*item_info)
        self._objects[index]=item_object
        self.select(index)
    
    def set_object(self,index,item_object):
        '''Aggiunge l'oggetto in posizione index e lo visualizza. 
        Il vecchio oggetto in posizione 'index' viene distrutto.'''
        del self._objects[index]
        self._objects[index]=item_object
        self.update_item(index)        
    
    def update_item(self,index):
        '''Aggiorna la visualizzazione con l'oggetto in posizione 'index'.'''
        item_info=self._get_param(self._objects[index])
        self.set_item(index, *item_info)
    
    def refresh_selected(self):
        item_info=self._get_param(self.get_selected_object())
        self.set_item(self._current_item, *item_info)
    
    def refresh_item(self,item_index):
        item_info=self._get_param(self._get_object(item_index))
        self.set_item(item_index, *item_info)
    
    def set_item(self,index,item_info):
        i=0
        while i<len(item_info):
            self._list.SetStringItem(index,i,str(item_info[i]))
            i+=1
    
    def get_item(self,index):
        if index in self._objects:
            return self._objects[index]
        return None
    
    def add_item(self,item_info):    
        i=0
        index=self._list.InsertStringItem(sys.maxint,unicode(item_info[i]))
        i=i+1
        while i<len(item_info):
            self._list.SetStringItem(index,i,str(item_info[i]))
            i+=1        
        return index
    
    def enable_list(self,enable=True):
        self._list.Enable(enable)
    
    def set_list_size(self,size):
        self._list.SetInitialSize(size)        
    
    def set_managed_list(self,managed_list):
        del self._list
        self._list=None
        self._list=managed_list
        self._list.Bind(wx.EVT_LIST_ITEM_SELECTED,self._item_selected_handler)
        #self._selected_callback=callback_func
#        for evt in self._callback:
#            if evt !=wx.EVT_LIST_ITEM_SELECTED:
#                self._list.Bind(evt,self._event_handler)
    def _find_callback(self,evt_type):
        for evt,callback in self._callback.iteritems():
            if evt.typeId == evt_type:
                return callback
        return None
    
    def _event_handler(self,evt):
        evt_type=evt.GetEventType()
        item_index=evt.GetIndex()
        callback=self._find_callback(evt_type)
        if callable(callback):
            current_object=self._get_object(item_index)
            wx.CallAfter(callback,current_object,item_index)
    
    def _get_object(self,item_index):
        return self._objects[item_index]
    
    def _item_selected_handler(self,evt):
        '''Handler dell'evento wx.EVT_LIST_ITEM_SELECTED. '''
        print self.__class__.__name__,'on_item_selected'
        self._previous_item=self._current_item
        self._current_item=evt.GetIndex()
        self._event_handler(evt)        
#        if callable(self._callback[wx.EVT_LIST_ITEM_SELECTED]):
#            current_object=self.get_selected_object()
#            wx.CallAfter(self._selected_callback,current_object)
    
    def set_columns(self,columns_info):
        '''@param columns_info:  è di tipo Column(alias di ViewInfo). ha i campi
     format, heading, with, attr.'''
        self._columns_info=columns_info
        num_col=0
        self._list.ClearAll()
        for info in columns_info:            
            self._list.InsertColumn(col=num_col, format=info.format, heading=info.heading, width=info.width)
            #info.column=num_col
            num_col+=1
    
    def get_selected_object(self):
        '''Restituisce l'oggetto selezionato nella lista degli oggetti.
        Se nessun oggetto e' selezionato restituisce None.'''
        if not self._current_item in self._objects: 
            return None
        return self._objects[self._current_item]
        
    def select(self,index):
        '''Seleziona l'elemento nella posizione index. Genera l'evento ITEM_SELECTED.
        @return: bool'''
#        if index>=self._list.GetItemCount():
#            return False
        try:
            self._list.SetItemState(index,wx.LIST_STATE_FOCUSED,wx.LIST_STATE_FOCUSED)
            self._list.SetItemState(index,wx.LIST_STATE_SELECTED,wx.LIST_STATE_SELECTED)
            self._previous_item=self._current_item
            self._current_item=index
            return True
        except:
            return False
    
    def load(self,objects):        
        self.clear()
        for item in objects:
            info=self._get_param(item)
            index=self.add_item(*info)
            self._objects[index]=item        
    
    def clear(self):
        del self._objects
        self._objects={}
        self._current_item=-1
        return self._list.DeleteAllItems()
    
    def _get_param(self,item):        
        '''@return: una tupla con gli elementi da visualizzare nella lista. La tupla 
        contiene un elemento per ogni colonna della lista. '''
        attrs=[]
        for col in self._columns_info:
            attrs.append(self._get_attribute(item,col.attr))
        return (tuple(attrs),)
    
    def _get_attribute(self,item,attr):
        '''@param item: è un oggetto.
        @param attr: è un attributo dell'oggetto @item come stringa.(può essere un metodo)
        @return: il valore dell'attributo @item o il valore restituito da @item se è un metodo.
        '''  
        attribute=''        
        if isinstance(attr,basestring):
            attribute=getattr(item,attr)
        if isinstance(attr,tuple):
            attribute=item
            for a in attr:
                attribute=getattr(attribute,a)                
        if callable(attribute):
            return attribute()
        return attribute

    
#===============================================================================
# Wrapper class for ListCtrl
#===============================================================================
class ListCtrl(KoroListCtrl,_Viewer):
    '''@param columns_info:  è di tipo Column(alias di ViewInfo). ha i campi
    * format
    * heading
    * with
    * attr .
    '''
    def __init__(self,parent,columns_info=[],style=kLC_DEFAULT_STYLE,*args,**kwargs):
        
        KoroListCtrl.__init__(self,parent,style=style,*args,**kwargs)
        _Viewer.__init__(self)
        self.info=None
        self.insert_columns(columns_info)
    
    def insert_columns(self,columns_info):
        self.info=columns_info
        num_col=0
        self.ClearAll()
        for info in columns_info:            
            self.InsertColumn(col=num_col, format=info.format, heading=info.heading, width=info.width)
            info.column=num_col
            num_col+=1
    
    def clear(self):
        return self.DeleteAllItems()
    
    def _get_param(self,item):
        '''@return: una tupla con gli elementi da visualizzare nella lista. La tupla 
        contiene un elemento per ogni colonna della lista. '''
        attrs=[]
        for col in self.info:
            attrs.append(self._get_attribute(item,col.attr))
        return (tuple(attrs),)    
    
    def select(self,idx,on=True):
        '''Seleziona l'elemento nella posizione idx e sposta il focus sulla lista.'''
        self.SetFocus()
        self.SetItemState(idx,wx.LIST_STATE_FOCUSED,wx.LIST_STATE_FOCUSED)
        self.SetItemState(idx,wx.LIST_STATE_SELECTED,wx.LIST_STATE_SELECTED)
        #return self.Select(idx, on)
    
    def get_selected(self):
        return self.GetFirstSelected()
    
    def Append(self,args):
        i=0
        index=self.InsertStringItem(sys.maxint,unicode(args[i]))
        i=i+1
        while i<len(args):
            self.SetStringItem(index,i,str(args[i]))
            i+=1
        return index


#===============================================================================
# DateCtrl
#===============================================================================
class DateCtrl(wx.TextCtrl):
    FORMAT="%d/%m/%Y"
    def __init__(self,*args,**kwargs):
        bgcolor = kwargs.pop('bgcolor',mTE_DEFAULT_BGCOLOR)
        mstyle  = kwargs.pop('mstyle',mTE_DEFAULT_STYLE)
        wx.TextCtrl.__init__(self,style=wx.TAB_TRAVERSAL,*args,**kwargs)
        self._bgcolor = bgcolor
        self._mstyle = mstyle
        self.Bind(wx.EVT_CHAR,self.OnChar)
        self.Bind(wx.EVT_NAVIGATION_KEY,self.p)
        self.Bind(wx.EVT_TEXT,self.OnText)
        self.Bind(wx.EVT_KILL_FOCUS,self.OnKillFocus)
        self.SetMaxLength(10)
        #self.SetMellStyle(mstyle)
    def p(self,evt):
        print 'ccccc'

    def OnChar(self,evt):
        print self.__class__.__name__,'OnChar'
        key = evt.GetKeyCode()
        print key
                
        if (key == wx.WXK_TAB or key==wx.WXK_RETURN) and not evt.ShiftDown():
            self.Parent.Navigate()
            evt.Skip()
            return
        if (key == wx.WXK_TAB or key==wx.WXK_RETURN) and evt.ShiftDown():
            self.Parent.Navigate(wx.NavigationKeyEvent.IsBackward)
            evt.Skip()
            return
        val=wx.TextCtrl.GetValue(self)
        #val = tc.GetValue()

        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
            evt.Skip()
            return
        if not chr(key) in string.digits: return
        if len(val)==10: return
        if len(val)==2 or len(val)==5:
            self.AppendText("/")                           
        evt.Skip()
        return    
        
    def OnText(self,evt):
        print self.__class__.__name__,'OnText'
        evt.Skip()

    def OnKillFocus(self,evt):
        print self.__class__.__name__,'OnKillFocus'
        if self.isValid():
            self.SetBackgroundColour(self._bgcolor)
        else:
            self.SetBackgroundColour(mINVALID_BGCOLOR)
        self.Refresh()
        evt.Skip()
    
    def RestoreBgcolor(self):
        self.SetBackgroundColour(self._bgcolor)
        self.Refresh()

    def SetValue(self,val):
        '''@param val e' di tipo datetime_date.'''
        print self.__class__.__name__,'SetValue'        
        if isinstance(val,wx.DateTime):
            val=util.to_pydate(val)
        if val is None:
            val=''
        else:
            val=val.strftime(DateCtrl.FORMAT)                                            
        wx.TextCtrl.SetValue(self,val)
    
    def GetValue(self):
        val=wx.TextCtrl.GetValue(self)
        if len(val)==0:
            return None
        d=wx.DateTime()
        d.ParseFormat(val,DateCtrl.FORMAT)
        return util.to_pydate(d)

    def isValid(self):
        print self.__class__.__name__,'IsValid'
        val=wx.TextCtrl.GetValue(self)
        if val == "":
            return True
        d=wx.DateTime()
        d.ParseFormat(val,DateCtrl.FORMAT)
        return d.IsValid()


#===============================================================================
# KoroTimeCtrl
#===============================================================================
class KoroTimeCtrl(masked.TimeCtrl):
    FORMAT='24HHMM'
    def __init__(self,*args,**kwargs):
        bgcolor = kwargs.pop('bgcolor',mTE_DEFAULT_BGCOLOR)
        mstyle  = kwargs.pop('mstyle',mTE_DEFAULT_STYLE)
        masked.TimeCtrl.__init__(self,format=KoroTimeCtrl.FORMAT,displaySeconds=False,*args,**kwargs)#style=wx.TAB_TRAVERSAL,
        self._bgcolor = bgcolor
        self._mstyle = mstyle
    
    def set_value(self,val):
        self.SetValue(val)
    
    def get_value(self):
        return self.GetValue()
        

#===============================================================================
# LabelTimeCtrl
#===============================================================================
class LabelTimeCtrl(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING)
        time=KoroTimeCtrl(*args,**kwargs)
        KoroControl.__init__(self,lb,time,spacing,orientation)
    
    

gEVT_PICKER_TYPE=wx.NewEventType()
gEVT_PICKER=wx.PyEventBinder(gEVT_PICKER_TYPE,1)
gPI_DEFAULT_STYLE = 1
gPI_EDITABLE    = 2            
#===============================================================================
# gPickerCtrl
#===============================================================================
class gPickerCtrl(wx.PyWindow):
    def __init__(self,parent,id=wx.ID_ANY,size=(150,-1),style=gPI_DEFAULT_STYLE,maxlen=0,value='',*args,**kwargs):
        wx.PyWindow.__init__(self,parent,style=wx.TAB_TRAVERSAL)#,*args,**kwargs)
        self.__ctrl=kwargs.pop('ctrl',wx.TextCtrl)(self,size=size)
        #self.__ctrl.SetSize(size)
        x,y = self.__ctrl.GetSizeTuple()
        self.__btn=wx.Button(id=id,parent=self,size=(y-1,y-1),label='...',style=wx.NO_BORDER | wx.NO_3D)
        self.__ctrl.SetMaxLength(maxlen)
        if style & gPI_DEFAULT_STYLE:
            self.__ctrl.SetEditable(False)
            self.__ctrl.SetBackgroundColour(mREAD_ONLY_COLOR)
            self.__ctrl.Refresh()    
        
        s=wx.BoxSizer()
        s.Add(self.__ctrl)#,0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.FIXED_MINSIZE)
        self.Bind(wx.EVT_LEFT_DCLICK,self.on_picker,id=self.__btn.GetId())
        s.Add(self.__btn,0,wx.ALIGN_RIGHT|wx.FIXED_MINSIZE)
        self.Bind(wx.EVT_BUTTON,self.on_picker,id=self.__btn.GetId())
        self.Bind(wx.EVT_CHILD_FOCUS,self.prova)
        self.SetSizer(s)
        self.Layout()
    
    def prova(self,evt):
        print 'prova'
        self.__ctrl.SetFocus()
        evt.Skip()
    
    def onPicker(self,evt):
        evt.SetEventType(gEVT_PICKER_TYPE)
        evt.Skip(True)
    
    def GetValue(self):
        return self.__ctrl.GetValue()
        
    def SetValue(self,value):
        self.__ctrl.SetValue(value)
    
    def Clear(self):
        self.__ctrl.Clear()
    
#    def setTextCtrl(self,control):
#        assert isinstance(control,wx.TextCtrl)
#        size=self.__ctrl.Size
#        self.__ctrl=control
#        self.__ctrl.SetSize(size)
    
    def IsEmpty(self):
        return self.__ctrl.IsEmpty()

#===============================================================================
# CalendarPopup
#===============================================================================
class CalendarPopup(wx.PopupTransientWindow):
    """Adds a bit of text and mouse movement to the wx.PopupWindow"""
    def __init__(self, parent, style=wx.SIMPLE_BORDER):
        wx.PopupTransientWindow.__init__(self, parent, style)
        self.SetBackgroundColour("#BACAD0")
        s=wx.GridBagSizer(2,1)
        self.__st = st=wx.calendar.CalendarCtrl(self, -1, wx.DateTime_Now(),pos=(0,0))
        self.__closeBtn=wx.Button(self,wx.ID_CLOSE,size=(80,28))
        sz = st.GetBestSize()
        bsz=self.__closeBtn.GetBestSize()        
        self.SetSize( (sz.width+20, sz.height+56) )
        s.Add(self.__st,(0,0),flag=wx.ALL|wx.EXPAND,border=10)
        s.Add(self.__closeBtn,(1,0),flag=wx.ALIGN_CENTER,border=1)
        self.SetSizer(s)
        self.Layout()
        self.Bind(wx.calendar.EVT_CALENDAR, self.__on_calendar)
        self.Bind(wx.EVT_BUTTON, self.__on_close,id=wx.ID_CLOSE)
    
    def __on_calendar(self,evt):
        self.Parent.set_date(self.__st.GetDate())
        self.Show(False)
        evt.Skip()
        wx.CallAfter(self.Destroy)
    
    def __on_close(self,evt):
        self.Show(False)
        evt.Skip()
        wx.CallAfter(self.Destroy)


#===============================================================================
# gDatePickerCtrl
#===============================================================================
class gDatePickerCtrl(gPickerCtrl):
    def __init__(self,parent,id=wx.ID_ANY,size=(90,-1),style=gPI_EDITABLE,maxlen=0,value='',*args,**kwargs):
        gPickerCtrl.__init__(self,parent,id,size,style,maxlen,value,ctrl=DateCtrl,*args,**kwargs)
        #self.setTextCtrl(DateCtrl(self))
        #self.__format="%d/%m/%Y"
        #self.Bind(wx.calendar.EVT_CALENDAR,self.__on_calendar)
    
    def __on_calendar(self,evt):
        print 'dddddddd'
    
    def set_date(self,dt):
        if dt.IsValid():
            self.SetValue(dt)
    
    def on_picker(self,evt):
        print "picker "
        win = CalendarPopup(self)
        # Show the popup right below or above the button
        # depending on available screen space...
        btn = evt.GetEventObject()
        posx,posy = btn.ClientToScreen( (0,0) )
        sz =  btn.GetSize()
        win.SetPosition((posx+20,posy+20))
        win.Popup()
        print 'dopo show'
       

#def getDataPickerCtrlClass():
#    if 'wxMSW' in wx.PlatformInfo:
#        return wx.GenericDatePickerCtrl
#    return wx.DatePickerCtrl
#
#===============================================================================
# #class gDatePickerCtrl__old(getDataPickerCtrlClass()):
#===============================================================================
#    def __init__(self,*args,**kwargs):
#        wx.DatePickerCtrl.__init__(self,*args,**kwargs)
#        self.__format="%d/%m/%Y"
#    
#    def GetValue(self):
#        d=wx.DatePickerCtrl.GetValue(self)
#        if d.IsValid():
#            return d.Format(self.__format)
#        return ""
#    
#    def SetValue(self,value):
#        assert isinstance(value,basestring) or value is None,"controls.gDataPicker-"+str(type(value))+": errore tipo parametro"
#        d=wx.DateTime()
#        if value is None :
#            value=""
#        d.ParseFormat(value,self.__format)
#        wx.DatePickerCtrl.SetValue(self,d)        

KTB_DEFAULT_STYLE=wx.NO_BORDER | wx.TB_TEXT
#===============================================================================
# ToolBar TODO:sistemare ToolBar
#===============================================================================
class ToolBar(wx.ToolBar):
    def __init__(self,*args,**kwargs):
        kwargs['style']=kwargs.pop('style',KTB_DEFAULT_STYLE)
        wx.ToolBar.__init__(self,*args,**kwargs)
        self._tools=[]
        #self.SetToolBitmapSize(wx.Size(16,16))      
    
    def add_label_tool(self,id_,label_,bitmap_):
        tool_id=self.AddLabelTool(id_, label_, bitmap_).GetId()
        self._tools.append(tool_id)
        return tool_id
    
    def add_control(self,control):
        tool_id=self.AddControl(control).GetId()
        self._tools.append(tool_id)
        return tool_id
    
    def add_separator(self):
        tool_id=self.AddSeparator().GetId()
        self._tools.append(tool_id)
        return tool_id
    
    def set_label_tool(self,id_,label_,bitmap_):
        tool_id=self.AddLabelTool(id_, label_, bitmap_).GetId()
        #self._tools.append(tool_id)
        return tool_id
    
    def set_separator(self):
        tool_id=self.AddSeparator().GetId()
        #self._tools.append(tool_id)
        return tool_id
    
    def reset_default(self,delete=True):
        delete=self.RemoveTool
        if delete:
            delete=self.DeleteTool
        for tool in self._tools:
            delete(tool)
        del self._tools
        self._tools=[]
    
    def realize(self):
        return self.Realize()
    
    def enable_tool(self,tool_id,enable=True):
        return self.EnableTool(tool_id,enable)
    
    def delete_tool(self,tool_id):
        self.DeleteTool(tool_id)


APPEND=-1
class KoroToolBar(ToolBar):
    def __init__(self,parent):
        ToolBar.__init__(self,parent)
        self._tool_map={}
    
    def show_tool(self,tool_id,show=True,pos=APPEND):
        if tool_id not in self._tool_map and tool_id==wx.ID_SAVE:
            self.insert_label_tool(1,tool_id, "Conferma", images.getDBUpdate32Bitmap())
        if show and self.GetToolPos(tool_id)==wx.NOT_FOUND and pos==APPEND :
            self.AddToolItem(self._tool_map[tool_id])
            self.Realize()
        elif show and self.GetToolPos(tool_id)==wx.NOT_FOUND and pos!=APPEND:
            self.InsertToolItem(pos,self._tool_map[tool_id])
            self.Realize()
        elif not show and self.GetToolPos(tool_id)!=wx.NOT_FOUND:
            self._tool_map[tool_id]=self.RemoveTool(tool_id)
    
    def add_label_tool(self,t_id,t_label,t_bitmap):
        self._tool_map[t_id]=self.AddLabelTool(t_id, t_label, t_bitmap)
        self.Realize()
    
    def insert_label_tool(self,pos,t_id,t_label,t_bitmap):
        self._tool_map[t_id]=self.InsertLabelTool(pos,t_id, t_label, t_bitmap)
        self.Realize()
#===============================================================================
# KoroPageToolBar
#===============================================================================
class KoroPageToolBar(KoroToolBar):
    def __init__(self,parent):
        KoroToolBar.__init__(self,parent)
        self._tool_map={}
        self._tool_map[wx.ID_NEW]=self.AddLabelTool(wx.ID_NEW, "Nuovo", images.getDBAdd32Bitmap())
        #self._tool_map[wx.ID_SAVE]=self.AddLabelTool(wx.ID_SAVE, "Conferma", images.getDBUpdate32Bitmap())
        self._tool_map[wx.ID_DELETE]=self.AddLabelTool(wx.ID_DELETE, "Elimina", images.getDelete24Bitmap())      
        #self.RemoveTool(wx.ID_SAVE)


#class KoroToolWrapper(object):
#    def __init__(self,tool,pos):
#        self.tool=tool
#        self.position=pos
#
##===============================================================================
## DefaultToolBar
##===============================================================================
#class DefaultToolBar(ToolBar):
#    def __init__(self,parent):
#        ToolBar.__init__(self,parent)
#        self._tool_map={}
#        tool1=self.AddLabelTool(wx.ID_NEW, "Nuovo", wx.ArtProvider_GetBitmap(wx.ART_NEW,wx.ART_TOOLBAR))
#        self._tool_map[wx.ID_NEW]=KoroToolWrapper(tool1,self.GetToolPos(wx.ID_NEW))
#        
#        tool2=self.AddLabelTool(wx.ID_SAVE, "Conferma", wx.ArtProvider_GetBitmap(wx.ART_FILE_SAVE,wx.ART_TOOLBAR))
#        self._tool_map[wx.ID_SAVE]=KoroToolWrapper(tool2,self.GetToolPos(wx.ID_SAVE))
#        
#        tool3=self.AddLabelTool(wx.ID_DELETE, "Elimina", wx.ArtProvider_GetBitmap(wx.ART_DELETE,wx.ART_TOOLBAR))
#        self._tool_map[wx.ID_DELETE]=KoroToolWrapper(tool3,self.GetToolPos(wx.ID_DELETE))
#        
#        self.RemoveTool(wx.ID_SAVE)
#    
#    def show_tool(self,tool_id,show=True):
#        if show:
#            self.InsertToolItem(self._tool_map[tool_id].position,
#                                self._tool_map[tool_id].tool)
#            self.Realize()
#        else:
#            self._tool_map[tool_id].position=self.GetToolPos(tool_id)
#            self.RemoveTool(tool_id)


#===============================================================================
# KoroListPageToolBar
#===============================================================================
class KoroListPageToolBar(KoroPageToolBar):
    def __init__(self,parent):
        KoroPageToolBar.__init__(self,parent)
        #self.AddLabelTool(wx.ID_NEW, "Nuovo", images.getDBAdd32Bitmap())
        self.insert_label_tool(1,wx.ID_EDIT, "Visualizza", images.getViewText32Bitmap())
        #self.AddLabelTool(wx.ID_DELETE, "Elimina", images.getDelete24Bitmap())
        self.AddSeparator()
        self.add_label_tool(wx.ID_PRINT, "Stampa", images.getPrint32Bitmap())
        #self.EnableTool(wx.ID_PRINT,False)#not yet implemented

class KoroMovMagazToolBar(KoroToolBar):
    def __init__(self,parent):
        KoroToolBar.__init__(self,parent)
        self.AddLabelTool(wx.ID_NEW, "Carica", images.getTabNew32Bitmap())
        self.AddLabelTool(wx.ID_NEW, "Scarica", images.getTabRemove32Bitmap())
        self.AddSeparator()
        self.AddLabelTool(wx.ID_DELETE, "Elimina", images.getDelete24Bitmap())
        self.add_label_tool(wx.ID_PRINT, "Stampa", images.getPrint32Bitmap())
        self.EnableTool(wx.ID_PRINT,False)#not yet implemented

TB_STYLE=wx.TB_FLAT|wx.TB_HORZ_LAYOUT

#===============================================================================
# DettaglioToolBar
#===============================================================================
class DettaglioToolBar(ToolBar):    
    def __init__(self,parent):
        ToolBar.__init__(self,parent,style=KTB_DEFAULT_STYLE|TB_STYLE)
        self.AddLabelTool(wx.ID_NEW, " Nuova Riga", images.getAdd16Bitmap())
        self.AddLabelTool(wx.ID_DELETE, " Elimina Riga", images.getRem16Bitmap())
        
#===============================================================================
# DocumentiToolBar
#===============================================================================
class DocumentoToolBar(ToolBar):
    def __init__(self,parent):
        ToolBar.__init__(self,parent,style=KTB_DEFAULT_STYLE|TB_STYLE)
        self.AddLabelTool(wx.ID_CLOSE, " Chiudi", images.getExit16Bitmap())
        #self.Realize()

##===============================================================================
## TableToolBar
##===============================================================================
#class TablePanelToolBar(ToolBar):
#    BITMAP_SIZE=(16,16)
#    def __init__(self,parent):
#        ToolBar.__init__(self,parent,style=KTB_DEFAULT_STYLE|TB_STYLE)
#        self.AddLabelTool(wx.ID_CLOSE, " Chiudi", wx.ArtProvider_GetBitmap(wx.ART_CROSS_MARK,wx.ART_TOOLBAR,TablePanelToolBar.BITMAP_SIZE))
#    
#    def add_label_tool(self,id_,label_,bitmap_):
#        return self.AddLabelTool(id_,' '+label_,wx.ArtProvider_GetBitmap(bitmap_,wx.ART_TOOLBAR,TablePanelToolBar.BITMAP_SIZE))


##===============================================================================
## ButtonPanel TODO:mai usata....
##===============================================================================
#class ButtonPanel(bp.ButtonPanel):
#    '''classe wrapper per wx.lib.agw.buttonpanel.ButtonPanel.'''
#    BITMAP_SIZE=(16,16)
#    def __init__(self,*args,**kwargs):
#        bp.ButtonPanel.__init__(self,*args,**kwargs)
#        bp_art = self.GetBPArt()
#        bp_art.SetColor(bp.BP_BACKGROUND_COLOR,wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
#        #bp_art.SetColor(bp.BP_BORDER_COLOR, wx.Colour(120,23,224))
#        #bp_art.SetColor(bp.BP_GRADIENT_COLOR_FROM, wx.Colour(60,11,112))
#        #bp_art.SetColor(bp.BP_GRADIENT_COLOR_TO, wx.Colour(120,23,224))
#        bp_art.SetGradientType(bp.BP_GRADIENT_VERTICAL)
#        self.SetStyle(bp.BP_USE_GRADIENT)
#    
#    
#    
#    def add_button(self,alignment=bp.BP_BUTTONTEXT_ALIGN_RIGHT,art=None,*args,**kwargs):
#        '''Accetta come argomenti gli stessi di wx.lib.agw.buttonpanel.ButtonInfo 
#        piu' il parametro alignment per cambiare l'allineamento del testo rispetto alla bitmap
#        e il parametro art in alternativa a bmp. Se art e' diverso da None bmp verra' ignorato.
#        Restituisce l'id del Button aggiunto.'''
#        if art is not None:
#            kwargs['bmp']=wx.ArtProvider_GetBitmap(art,wx.ART_TOOLBAR,ButtonPanel.BITMAP_SIZE)
#        btn=bp.ButtonInfo(self,*args,**kwargs)
#        btn.SetTextAlignment(alignment)
#        self.AddButton(btn)
#        return btn
#    
#    def bind(self,event,handler,source=None,id=-1,id2=-1):
#        pass
#        


##===============================================================================
## PrezziProdottoTable
##===============================================================================
#class PrezziProdottoTable(gridlib.PyGridTableBase):
#    def __init__(self):
#        gridlib.PyGridTableBase.__init__(self)
#
#        self.colLabels = ['Listino','Prezzo','Ricarico']
#
#        self.dataTypes = [gridlib.GRID_VALUE_STRING,
#                          gridlib.GRID_VALUE_FLOAT + ':10,2',
#                          gridlib.GRID_VALUE_STRING
#                          ]
#        
#        observer=wx.GetApp().get_observer()
#        observer.set_context('LISTINI')
#        listini=observer.get_objects()
#        
#        self.data = []
#        for listino in listini:
#            str_ricarico="No"
#            if listino.has_flag_ricarico():
#                str_ricarico="{0}% su {1}".format(listino.ricarico,listino.codice_listino_ricarico)            
#            self.data.append([listino.codice,0,str_ricarico])    
#    
#    #--------------------------------------------------
#    # required methods for the wxPyGridTableBase interface
#
#    def GetNumberRows(self):
#        return len(self.data)
#
#    def GetNumberCols(self):
#        return 3#len(self.data[0])
#
#    def IsEmptyCell(self, row, col):
#        try:
#            return not self.data[row][col]
#        except IndexError:
#            return True
#
#    # Get/Set values in the table.  The Python version of these
#    # methods can handle any data-type, (as long as the Editor and
#    # Renderer understands the type too,) not just strings as in the
#    # C++ version.
#    def GetValue(self, row, col):
#        try:
#            return self.data[row][col]
#        except IndexError:
#            return ''
#    
#    def SetData(self,data):
#        assert isinstance(data,list)
#        for item in data:
#            for i in range(len(self.data)):
#                if item.fk_listino==self.data[i][0]:
#                    self.SetValue(i, 1, item.prezzo)
#                    if item.listino.has_flag_ricarico():
#                        self.GetView().SetReadOnly(i,1)
#
#    def SetValue(self, row, col, value):
#        print 'prezzi table setvalue'
#        def innerSetValue(row, col, value):
#            try:
#                self.data[row][col] = value                
#            except IndexError:
#                # add a new row
#                self.data.append([''] * self.GetNumberCols())
#                innerSetValue(row, col, value)
#
#                # tell the grid we've added a row
#                msg = gridlib.GridTableMessage(self,            # The table
#                        gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED, # what we did to it
#                        1                                       # how many
#                        )
#
#                self.GetView().ProcessTableMessage(msg)
#        innerSetValue(row, col, value) 
#
#    #--------------------------------------------------
#    # Some optional methods
#
#    # Called when the grid needs to display labels
#    def GetColLabelValue(self, col):
#        return self.colLabels[col]
#
#    # Called to determine the kind of editor/renderer to use by
#    # default, doesn't necessarily have to be the same type used
#    # natively by the editor/renderer if they know how to convert.
#    def GetTypeName(self, row, col):
#        return self.dataTypes[col]
#
#    # Called to determine how the data can be fetched and stored by the
#    # editor and renderer.  This allows you to enforce some type-safety
#    # in the grid.
#    def CanGetValueAs(self, row, col, typeName):
#        colType = self.dataTypes[col].split(':')[0]
#        if typeName == colType:
#            return True
#        else:
#            return False
#
#    def CanSetValueAs(self, row, col, typeName):
#        return self.CanGetValueAs(row, col, typeName)
#
#    def Clear(self):
#        print "table clear"
#        for i in range(len(self.data)):
#            self.SetValue(i,1,0)
#
#
##===============================================================================
## gPrezziProdottoGrid
##===============================================================================
#class gPrezziProdottoGrid(gridlib.Grid):
#    def __init__(self, parent):
#        gridlib.Grid.__init__(self, parent, -1)
#    
#        table = PrezziProdottoTable()
#
#        # The second parameter means that the grid is to take ownership of the
#        # table and will destroy it when done.  Otherwise you would need to keep
#        # a reference to it and call it's Destroy method later.
#        gridlib.Grid.SetTable(self,table, True)
#        for i in range(table.GetNumberRows()):
#            self.SetReadOnly(i,0)
#            self.SetReadOnly(i,2)
#        self.AutoSizeColumns(True)
#        self.SetRowLabelSize(1)
#        self.SetColSize(0,200)
#        self.SetMargins(0,0)
#        
#        self.Layout()
#
#        gridlib.EVT_GRID_CELL_LEFT_DCLICK(self, self.OnLeftDClick)
#        
#    # I do this because I don't like the default behaviour of not starting the
#    # cell editor on double clicks, but only a second click.
#    def OnLeftDClick(self, evt):
#        if self.CanEnableCellControl():
#            self.EnableCellEditControl()
#    
#    def SetCellValue(self,row,col,value):
#        self.GetTable().SetValue(row,col,value)
#    
#    def SetRowTuple(self,row,tupleVal):
#        assert isinstance(tupleVal,tuple),"Tipo tupla atteso."
#        self.GetTable().SetValue(row,0,tupleVal[0])
#        self.GetTable().SetValue(row,1,tupleVal[1])
#    
#    def GetRowTuple(self,row):
#        t=self.GetTable()
#        return (t.GetValue(row,0),t.GetValue(row,1))
#    
#    def SetTableData(self,data):
#        self.GetTable().SetData(data)
#    
#    def GetTableData(self):
#        return self.GetTable().data


#===============================================================================
# TotaliCtrl
#===============================================================================
class TotaliCtrl(wx.StaticBoxSizer):
    def __init__(self,parent):
        super(TotaliCtrl,self).__init__(wx.StaticBox(parent,-1," TOTALI ".upper()),wx.VERTICAL)
        self.AddSpacer(2)
        
        orboxsizer=wx.BoxSizer()
        self.totale_imponibile = wx.StaticText(parent,label='0.00')
        orboxsizer.Add(wx.StaticText(parent,label='Imponibile'),1,wx.ALIGN_LEFT|wx.EXPAND)
        orboxsizer.AddStretchSpacer(2)
        #orboxsizer.Add(wx.StaticText(parent,label='€ '),0)
        orboxsizer.Add(self.totale_imponibile,0,wx.ALIGN_RIGHT|wx.EXPAND)
        self.Add(orboxsizer,0,wx.ALL|wx.EXPAND,border=4)
        
        orboxsizer=wx.BoxSizer()
        self.totale_iva = wx.StaticText(parent,label='0.00')
        orboxsizer.Add(wx.StaticText(parent,label='Iva'),1,wx.ALIGN_LEFT|wx.EXPAND)
        orboxsizer.AddStretchSpacer(2)
        #orboxsizer.Add(wx.StaticText(parent,label='€ '),0)
        orboxsizer.Add(self.totale_iva,0,wx.ALIGN_RIGHT|wx.EXPAND)
        self.Add(orboxsizer,0,wx.ALL|wx.EXPAND,border=4)
        
        orboxsizer=wx.BoxSizer()
        self.totale = wx.StaticText(parent,label='0.00')
        font=self.totale.GetFont()
        font.SetWeight(wx.FONTWEIGHT_BOLD)
        self.totale.SetFont(font)
        label=wx.StaticText(parent,label='Totale')
        label.SetFont(font)
        orboxsizer.Add(label,1,wx.ALIGN_LEFT|wx.EXPAND)
        orboxsizer.AddStretchSpacer(2)
        #label=wx.StaticText(parent,label='€ ')
        #label.SetFont(font)
        #orboxsizer.Add(label,0)
        orboxsizer.Add(self.totale,0,wx.ALIGN_RIGHT)
        self.Add(orboxsizer,0,wx.ALL|wx.EXPAND,border=4)
    
    def set_totale(self,value):
        self.totale.SetLabel(str(value))
    
    def set_totale_imponibile(self,value):
        self.totale_imponibile.SetLabel(str(value))
    
    def set_totale_iva(self,value):
        self.totale_iva.SetLabel(str(value))
    
    def reset(self):
        self.totale_imponibile.SetLabel('0.00')
        self.totale_iva.SetLabel('0.00')
        self.totale.SetLabel('0.00')
        self.Layout()


#===============================================================================
# SpeseCtrl
#===============================================================================
class SpeseCtrl(wx.BoxSizer):
    def __init__(self,parent):
        wx.BoxSizer.__init__(self,wx.HORIZONTAL)
        
        self.ctrl_descrizione_spese=LabelComboBox(parent,label='Spese',size=(200,25),orientation=wx.VERTICAL)
        self.Add(self.ctrl_descrizione_spese,0)
        self.AddSpacer(5)
        self.ctrl_iva_spese=IvaCtrl(parent,orientation=wx.VERTICAL)
        self.Add(self.ctrl_iva_spese,0)
        self.AddSpacer(5)
        self.ctrl_importo_spese=KValutaCtrl(parent,label='Importo',size=(100,25),orientation=wx.VERTICAL)
        self.Add(self.ctrl_importo_spese,0)
        self.Layout()
        self._enable(None)
        self.ctrl_descrizione_spese.bind(wx.EVT_TEXT,self._enable)
    
    def _enable(self,evt):
        if self.ctrl_descrizione_spese.get_value()=='':
            self.ctrl_iva_spese.enable(False)
            self.ctrl_importo_spese.enable(False)
            self.ctrl_importo_spese.clear()
        else:
            self.ctrl_iva_spese.enable(True)
            self.ctrl_importo_spese.enable(True)
   
    def set_spese(self,descr,iva,importo):
        self.ctrl_descrizione_spese.set_value(descr)
        self.ctrl_iva_spese.set_string_selection(iva)
        self.ctrl_importo_spese.set_value(importo)
        self._enable(None)
    
    def get_descrizione(self):
        return self.ctrl_descrizione_spese.get_value()
    
    def get_iva(self):
        return self.ctrl_iva_spese.get_selected_object()
    
    def get_importo(self):
        return self.ctrl_importo_spese.get_value()
    
    def clear(self):
        self.ctrl_descrizione_spese.clear()
        self.ctrl_importo_spese.clear()
        self.ctrl_iva_spese.select_default()
        self._enable(None)
    
    def get_value(self):
        return (self.get_descrizione(),self.get_iva(),self.get_importo())
    
    def get_importo_ctrl(self):
        return self.ctrl_importo_spese
    
    def bind(self,event,handler,source=None,id=-1,id2=-1):
        self.ctrl_descrizione_spese.bind(event,handler)
        self.ctrl_importo_spese.bind(event,handler)


#class ObjectChoiceCtrl(LabelChoice):
#    def __init__(self,*args,**kwargs):
#        LabelChoice.__init__(self,*args,**kwargs)
#        self._default=''
#        self._object={}
#    
#    def _request_objects(self):
#        pass
#    
#    def _load(self,objects):
#        self._default=observer.get_option('IVA_DEFAULT')
#        self._object={}
#        for obj in objects:
#            self._object[obj.codice]=obj
#        self.control.SetItems(self._iva.keys())


#===============================================================================
# IvaCtrl
#===============================================================================
class IvaCtrl(LabelObjectChoice):
    def __init__(self,*args,**kwargs):
        label=kwargs.pop('label','Iva')
        LabelObjectChoice.__init__(self,label=label,size=(90,25),view='codice',*args,**kwargs)
        observer=wx.GetApp().get_observer()
        observer.set_context('ALIQUOTE_IVA')
        iva=observer.get_objects()
        self.load(iva)
        self._default=observer.get_option('IVA_DEFAULT')
        self.select_default()
    
    def select_default(self):
        self.control.SetStringSelection(self._default)
    
    def clear(self):
        self.select_default()
    
    def get_selected_object(self):
        return self.control.get_selected_object()
    
    def get_percentuale(self):
        return self.get_selected_object().aliquota
    
    def set_value(self,obj):
        if obj is None:
            self.select_default()
        else:
            LabelObjectChoice.set_value(self,obj)
    


#===============================================================================
# ListinoCtrl
#===============================================================================
class ListinoCtrl(LabelObjectChoice):
    '''Controllo che permette la scelta dei listini disponibili.
    Per abilitare la scelta di un valore nullo, usare il parametro 'allow_null=True'.
    Se 'allow_null==False' il listino selezionato di default è il listino di vendita impostato nelle opzioni.
    Per cambiare il listino di default usare il parametro 'context=ListinoCtrl.ACQUISTO'. '''
    
    VENDITA='VENDITA'
    ACQUISTO='ACQUISTO'
    
    def __init__(self,*args,**kwargs):
        label=kwargs.pop('label','Listino')
        context=kwargs.pop('context',ListinoCtrl.VENDITA)
        LabelObjectChoice.__init__(self,label=label,size=(150,25),view='nome',*args,**kwargs)
        self._default=None
#        f=self.control.GetFont()
#        f.SetPointSize(8)
#        self.control.SetFont(f)
        self._load_objects()
        self.set_context(context)
    
    def _load_objects(self):
        observer=wx.GetApp().get_observer()
        observer.set_context('LISTINI')        
        listini=observer.get_listini()        
        self.load(listini)
#        if not self.is_null_allowed():
#            self._default=listini[0]
#        self.select_default()
#        self._default=observer.get_option('LISTINO_DEFAULT_{0}_NAME'.format(tipo))
#        self.select_default()
    
    def set_context(self,context):
        if self.is_null_allowed():
            return
        observer=wx.GetApp().get_observer()
        default_ID=observer.get_option('LISTINO_DEFAULT_{0}'.format(context))
        self._default=observer.get_object(ID=default_ID)
        self.select_default()
            
    def select_default(self):
            self.control.set_value(self._default)
    
    def clear(self):
        self.select_default()
    
    def refresh_listini(self):
        self._load_objects()
    
    def set_value(self,value):
        if value is None:
            self.select_default()
        else:
            super(ListinoCtrl,self).set_value(value)
    
#    def get_selected_object(self):
#        return self.control.get_selected_object()


#LISTINO_VENDITA='VENDITA'
#LISTINO_ACQUISTO='ACQUISTO'
#class ListinoCtrl_old(LabelObjectChoice):
#    '''Controllo che permette la scelta dei listini disponibili.
#    Di default è un listino di vendita. Per cambiare tipo usare il metodo set_tipo()
#    oppure usare il parametro 'tipo' durante la creazione.
#    '''
#    def __init__(self,*args,**kwargs):
#        tipo=kwargs.pop('tipo',LISTINO_VENDITA)
#        LabelObjectChoice.__init__(self,label='Listino',size=(150,25),view='codice',*args,**kwargs)
#        f=self.control.GetFont()
#        f.SetPointSize(8)
#        self.control.SetFont(f)
#        observer=wx.GetApp().get_observer()
#        observer.set_context('LISTINI')
#        listini=observer.get_objects()
#        self.load(listini)
#        self._default=observer.get_option('LISTINO_DEFAULT_{0}'.format(tipo))
#        self.select_default()
#    
#    def set_tipo(self,tipo):
#        observer=wx.GetApp().get_observer()
#        self._default=observer.get_option('LISTINO_DEFAULT_{0}'.format(tipo))
#        self.select_default()
#            
#    def select_default(self):
#        self.control.SetStringSelection(self._default)
#    
#    def clear(self):
#        self.select_default()
#    
#    def get_selected_object(self):
#        return self.control.get_selected_object()
#    

EVT_AFTER_LOOKUP=wx.NewEventType()
KEVT_AFTER_LOOKUP_CANCEL=wx.NewEventType()
#===============================================================================
# LookupCtrl
#===============================================================================
class LookupCtrl(wx.SearchCtrl,_ObjectViewer):
    def __init__(self,*args,**kwargs):
        self._lookup_context=kwargs.pop('context',None)
        view=kwargs.pop('view')
        self.after_lookup=kwargs.pop('after_lookup',None)
        self.after_lookup_cancel=None
        kwargs['style']=kwargs.pop('style',wx.TE_READONLY)
        wx.SearchCtrl.__init__(self,*args,**kwargs)#
        _ObjectViewer.__init__(self,view)
        self.SetSearchBitmap(wx.ArtProvider_GetBitmap(wx.ART_FIND,wx.ART_MENU))
        self.SetDescriptiveText('')
        self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN,self.lookup)
        self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN,self._cancel_lookup_handler)
        #self.Bind(wx.EVT_TEXT, self._text_changed_handler)
        self.Bind(wx.EVT_TEXT_ENTER, self._on_char_handler)
        self.filter=None
        self._opt = VENDITA
    
    def _on_char_handler(self,evt):
        print 'on_char lookupcontrol'
        key=evt.GetKeyCode()
        if (key==wx.WXK_TAB or key==wx.WXK_RETURN) and not evt.ShiftDown():
            self.Parent.Navigate()
            evt.Skip()
            return
        if (key==wx.WXK_TAB or key==wx.WXK_RETURN) and evt.ShiftDown():
            self.Navigate(wx.NavigationKeyEvent.IsBackward)
            evt.Skip()
            return
        evt.Skip()
        
    
#    def _text_changed_handler(self,evt):
#        self.set_object(None)
#        evt.Skip(True)        
    
    def _cancel_lookup_handler(self,evt):
        self.change_value(None)
        if callable(self.after_lookup_cancel):
            wx.CallAfter(self.after_lookup_cancel)
    
    def set_filter(self,filter):
        self.filter=filter
    
    def lookup(self,evt):
        win=self._lookup_context(self.Parent, 
                                 filter = self.filter,
                                 opt = self._opt)
        if win.show()!=wx.ID_CANCEL:
            obj=win.get_selection()
            if callable(self.after_lookup):
                wx.CallAfter(self.after_lookup,obj)
            self._set_value(obj)
        win.Destroy()
    
    def get_string_value(self):
        return self.GetValue()
    
    def set_string_value(self,value):
        self.set_object(None)
        self.ChangeValue(value)
    
    def change_value(self,value):
        self.set_object(value)
        self.ChangeValue(self.get_view())
    
    def set_value(self,value):
        self.ChangeValue('')
        self.set_object(value)
        self.ChangeValue(self.get_view())
    
    def _set_value(self,value):
        self.ChangeValue('')
        self.set_object(value) 
        #CallAfter per chiamare SetFocus dopo self.lookup(...)
        wx.CallAfter(self._after_set_value)
          
    def _after_set_value(self): 
        self.SetFocus() 
        self.ChangeValue(self.get_view())
    
    def set_lookup_context(self, context, opt = VENDITA):
        self._lookup_context=context
        self._opt = opt
    
    def bind(self,event, handler, source=None, id=-1, id2=-1):
        if event==EVT_AFTER_LOOKUP:
            self.after_lookup=handler
        elif event==KEVT_AFTER_LOOKUP_CANCEL:
            self.after_lookup_cancel=handler
        else:
            self.Bind(event, handler, source, id, id2)
    
    def SetValue(self,val):
        raise Exception('LookupCtrl.SetValue:Metodo non disponibile')
        

EVT_LOOKUP=wx.EVT_SEARCHCTRL_SEARCH_BTN
#===============================================================================
# LabelLookupCtrl
#===============================================================================
class LabelLookupCtrl(KoroControl):
    def __init__(self,*args,**kwargs):
        lb=kwargs.pop('label','')
        orientation=kwargs.pop('orientation',wx.HORIZONTAL)
        spacing=kwargs.pop('spacing',DEFAULT_SPACING)
        text=LookupCtrl(*args,**kwargs)        
        KoroControl.__init__(self,lb,text,spacing,orientation)
    
    def set_filter(self,filter):
        self.control.set_filter(filter)
    
    def clear(self):
        self.control.Clear() 
      
    def enable(self,enable=True):
        self.control.Enable(enable)
    
    def get_value(self):
        val = self.control.get_object()
        if val is None:
            val = self.get_string_value()
        return val
    
    def get_string_value(self):
        return self.control.GetValue()
    
    def set_string_value(self, value):
        self.control.set_string_value(value)
    
    def set_value(self,value):#prende un oggetto
        self.control.set_value(value)        
    
    def set_lookup_context(self,context, opt = VENDITA):
        self.control.set_lookup_context(context, opt)
    
    def show_cancel_button(self,show=True):
        self.control.ShowCancelButton(show)
    
    def bind(self,*args,**kwargs):
        self.control.bind(*args,**kwargs)


#-------------------- NUOVI CONTROLLI DI KORO 13/10/2011 --------------------#

#===============================================================================
# KObjectRenderer
#===============================================================================
class KObjectRenderer(object):
    def __init__(self):        
        self._object=None        
    
    def set_object(self,obj):
        self._object=obj
        self._render_object()
    
    def get_object(self):
        return self._object
            
    def _render_object(self):
        raise Exception('Not Implemented')
    
    object=property(get_object,set_object)


#===============================================================================
# KObjectContainer
#===============================================================================
class KObjectContainer(object):
    def __init__(self,allow_null=False):
        self._allow_null=allow_null
    
    def load(self,objects):
        '''Carica gli elementi gestiti dal controllo. 
        Il parametro objects è una lista di wx.ItemContainer.'''
        self.clear()
        if self.is_null_allowed():
            self.append(None)
        for obj in objects:
            self.append(obj)
    
    def append(self,item):
        '''Override in subclass'''
        raise Exception('Not Implemented')
    
    def clear(self):
        '''Override in subclass'''
        raise Exception('Not Implemented')
    
    def is_null_allowed(self):
        return self._allow_null

    
#===============================================================================
# KControlBase
#===============================================================================
class KControlBase(wx.PyControl):
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL, 
                 pos=wx.DefaultPosition, spacing=-2, style=0, 
                 name=wx.ControlNameStr):
        wx.PyControl.__init__(self,parent,id,pos,style=wx.NO_BORDER)        
        self.SetSizer(wx.GridBagSizer())
        self._next_row=0
        self._next_col=1
        self._orientation=orientation
        if orientation==wx.VERTICAL:
            self._next_row=1
            self._next_col=0
        if spacing==-2:
            spacing=DEFAULT_SPACING
        self._label=wx.StaticText(self,label=label,size=(spacing,-1))
        self.Sizer.Add(self._label, pos=(0, 0), flag=wx.ALIGN_CENTER_VERTICAL)
        self._control=None
        self.Bind(wx.EVT_SET_FOCUS, self._on_set_focus)
    
    def _on_set_focus(self,evt):
        self._control.SetFocus()
    
    def _to_camel_case(self,attr_name):
        if not attr_name[0].islower():
            return attr_name
        if '_' in attr_name:
            attr_name=attr_name.replace('_',' ')
            attr_name=attr_name.title()
            attr_name=attr_name.replace(' ','')
            return attr_name
        return attr_name.title()
    
    def __getattribute__(self,name):
        error=None
        try:
            return object.__getattribute__(self,name)
        except AttributeError,e:
            error=e
        try:
            return object.__getattribute__(self._control,self._to_camel_case(name))
        except:
            raise AttributeError(error)
    
    def _set_control(self,control):
        if self._control is None:
            self._control=control
            self.Sizer.Add(self._control, pos=self._next_sizer_cell())
            self._control.Bind(wx.EVT_CHAR,self._on_char)
    
    def _on_char(self,evt):
        print 'on_char kcontrolbase'
        key=evt.GetKeyCode()
        if (key==wx.WXK_TAB or key==wx.WXK_RETURN) and not evt.ShiftDown():
            self.Navigate()
            evt.Skip()
            return
        if (key==wx.WXK_TAB or key==wx.WXK_RETURN) and evt.ShiftDown():
            self.Navigate(wx.NavigationKeyEvent.IsBackward)
            evt.Skip()
            return
        evt.Skip()
    
    def _next_sizer_cell(self):
        cell=(self._next_row,self._next_col)
        self._next_col+=1
        return cell
    
    def is_vertical(self):
        return self._orientation==wx.VERTICAL
    
    def set_label(self,label):
        self._label.SetLabel(label)
    
    def clear(self):
        self._control.Clear()
    
    def set_focus(self):
        self._control.SetFocus()
    
    def DoGetBestSize(self):
        label_size=self._label.GetSize()
        ctrl_size=self._control.GetSize()
        w=0
        h=0
        if self.is_vertical():
            w=max([label_size.width,ctrl_size.width])
            h=label_size.height + ctrl_size.height
        else:
            w=label_size.width + ctrl_size.width
            h=max([label_size.height,ctrl_size.height])
        best=wx.Size(w+5,h+5)
        self.CacheBestSize(best)    
        return best
    
    def AcceptsFocusFromKeyboard(self):
        """Overridden base class virtual."""

        # We can accept focus from keyboard, obviously
        return True


    def AcceptsFocus(self):
        """ Overridden base class virtual. """

        return True

    def GetDefaultAttributes(self):
        """
        Overridden base class virtual.  By default we should use
        the same font/colour attributes as the native wx.CheckBox.
        """

        return self._control.GetClassDefaultAttributes()

    def ShouldInheritColours(self):
        """
        Overridden base class virtual.  If the parent has non-default
        colours then we want this control to inherit them.
        """

        return True

    
    
class KControlWithObject(KControlBase,KObjectRenderer):
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL, 
                 pos=wx.DefaultPosition, spacing=-2, style=0, 
                 name=wx.ControlNameStr):
        KControlBase.__init__(self, parent, id, label, orientation, pos, 
                              spacing, style, name)
        KObjectRenderer.__init__(self)

#===============================================================================
# KControl
#===============================================================================
class KControl(KControlWithObject):
    def __init__(self,*args,**kwargs):
        KControlWithObject.__init__(self,*args,**kwargs)
    
    def get_value(self):
        return self._control.GetValue()
    
    def set_value(self,value):
        self._control.SetValue(value)
    
    def _render_object(self):
        self.set_value(getattr(self._object,self.Name))
    
    value=property(get_value, set_value)


#===============================================================================
# KControlWithObjects
#===============================================================================
class KControlWithObjects(KControlBase,KObjectContainer):
    def __init__(self, parent, id=-1, label='', orientation=wx.HORIZONTAL, 
                 pos=wx.DefaultPosition, spacing=-2, null=False, 
                 name=wx.ControlNameStr):
        KControlBase.__init__(self, parent, id, label, orientation, pos, spacing,
                              name)
        KObjectContainer.__init__(self, null)


class KTextCtrl(KControl):
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, size=DEFAULT_SIZE, spacing=-2, 
                 style=0, maxlen=0,validator=wx.DefaultValidator, 
                 name=wx.ControlNameStr):
        KControl.__init__(self, parent, id, label, orientation, pos, spacing, name)
        self._set_control(wx.TextCtrl(self,size=size,style=style,
                                      validator=validator,name=name))
        self._control.SetMaxLength(maxlen)
        self.Layout()

        
#===============================================================================
# KChoice
#===============================================================================
class KChoice(KControlWithObjects):
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, size=DEFAULT_SIZE, spacing=-2, 
                 choices=[], style=0, null=False, 
                 validator=wx.DefaultValidator, name=wx.ControlNameStr):
        KControlWithObjects.__init__(self, parent, id, label, orientation, pos,
                                     spacing, null, name)        
        self._set_control(wx.Choice(self, size=_init_size(size), choices=choices, style=style,
                               validator=validator,name=name))
        self.Layout()
    
    def get_string_selection(self):
        return self._control.GetStringSelection()
    
    def set_string_selection(self,val):
        self._control.SetStringSelection(str(val))
    
    def get_selected_object(self):
        return self._control.GetClientData(self._control.GetCurrentSelection())
    
    def select_object(self,val):
        self.set_string_selection(getattr(val,self.Name))
    
    def select(self,index):
        self._control.SetSelection(index)
    
    def append(self,item):        
        self._control.Append(getattr(item,self.Name),item,'---')
    
    def clear(self):
        self._control.Clear()
    
    def get_selection(self):
        return self._control.GetSelection()
    
    value=property(get_string_selection, set_string_selection)
    object=property(get_selected_object, select_object)
    selection=property(get_selection,select)


#===============================================================================
# KDateCtrl
#===============================================================================
class KDateCtrl(KControlBase):
    def __init__(self,parent, id=-1, label='Data', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, spacing=-2, style=0 ):
        KControlBase.__init__(self, parent, id, label, orientation, pos, 
                              spacing, style, name=wx.ControlNameStr)
        self._set_control(wx.DatePickerCtrl(self,size=(120,25),
                                            style = wx.DP_DROPDOWN
                                            | wx.DP_SHOWCENTURY
                                            | wx.DP_ALLOWNONE )
                          )
        self.Layout()
        
    def get_value(self):
        return util.to_pydate(self._control.GetValue())
    
    def set_value(self,value):
        self._control.SetValue(util.to_wxdate(value))
    
    value=property(get_value, set_value)

#===============================================================================
# KTimeCtrl
#===============================================================================
class KTimeCtrl(KControlBase):
    FORMAT='24HHMM'
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, spacing=-2, style=0 ):
        KControlBase.__init__(self, parent, id, label, orientation, pos, 
                              spacing, style, name=wx.ControlNameStr)        
        self._set_control(masked.TimeCtrl(self,format=KoroTimeCtrl.FORMAT,
                                          displaySeconds=False)
                          )
        self.Layout()        
    
    def set_value(self,val):
        self.SetValue(val)
    
    def get_value(self):
        return self.GetValue()
    
    value=property(get_value, set_value)

FS_BEFORE=0
FS_AFTER=1
#===============================================================================
# KValutaCtrl
#===============================================================================
class KFloatCtrl(KControlBase):
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, size=DEFAULT_SIZE, spacing=-2, 
                 style=0, sign='',sign_pos=FS_BEFORE, maxlen=0,
                 validator=wx.DefaultValidator, name=wx.ControlNameStr):
        KControlBase.__init__(self, parent, id, label, orientation, pos, spacing, name)
        self._set_control(wx.TextCtrl(self,size=size))
        self._control.SetMaxLength(maxlen)
        #self._control.SetDefaultStyle(wx.TextAttr(alignment=wx.TE_RIGHT))        
        self.SIGN=sign
        self.SIGN_POS=sign_pos
        self._value='0,00'
        self.clear()
        self._control.Bind(wx.EVT_CHAR,self.on_char)
        self._control.Bind(wx.EVT_TEXT,self.on_text)
        self._control.Bind(wx.EVT_KILL_FOCUS,self.on_kill_focus)
        self._control.Bind(wx.EVT_SET_FOCUS, self.on_set_focus)
        self.Layout()
    
    def __fmt(self):
        before=''
        after=''
        if self.SIGN_POS==FS_BEFORE:
            before=self.SIGN+' '
        elif self.SIGN_POS==FS_AFTER:
            after=' '+self.SIGN
        return '{0}{1}{2}'.format(before,self._value,after)
    
    def _dot_dp(self,val):
        '''Dot decimal point'''
        return val.replace(',','.')
    
    def _comma_dp(self,val):
        '''Comma decimal point'''
        return val.replace('.',',')
    
    def set_value(self,value):
        self._value=self._comma_dp(str(value))
        self._control.ChangeValue(self.__fmt())
    
    def get_value(self):
        return self._dot_dp(self._value)

    def on_char(self,evt):
        print 'ValutaCtrl on_char'
        key=evt.GetKeyCode()
        #tc=evt.GetEventObject()
        
        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
            evt.Skip()
            return
        if chr(key) not in string.digits and chr(key) !=',':
            evt.Skip(False)                          
            return            
        evt.Skip()
        
    def on_text(self,evt):
        print 'ValutaCtrl on_text'
#        text=evt.GetString()
        self._value=evt.GetString()
        evt.Skip()

    def on_kill_focus(self,evt):
        print 'KValutaCtrl on_kill_focus'
#        if self._mstyle & mTE_UPPER:
#            wx.TextCtrl.SetValue(self,wx.TextCtrl.GetValue(self).upper())
#        if self._mstyle & mTE_TITLED:
#            wx.TextCtrl.SetValue(self,wx.TextCtrl.GetValue(self).title())
        val=self._value
        try:
            self._value=self._comma_dp(str(round(
                                                 Decimal(self._dot_dp(self._value))
                                                 )
                                           )
                                       )
        except:
            self._value=val            
        self._control.ChangeValue(self.__fmt())
        #self._control.SetDefaultStyle(wx.TextAttr(alignment=wx.TE_RIGHT))
        evt.Skip(True)
    
    def on_set_focus(self,evt):
        print 'ValutaCtrl on_set_focus'        
        #self._control.SetDefaultStyle(wx.TextAttr(alignment=wx.TE_LEFT))
        wx.CallAfter(self._after_set_focus)        
        self._control.ChangeValue(self._value)        
        evt.Skip(False)
    
    def _after_set_focus(self):
        self._control.SetInsertionPoint(0)
        self._control.SetSelection(-1,-1)
    
    def clear(self):
        self.set_value('0,00')
    
    value=property(get_value,set_value)


class KValutaCtrl(KFloatCtrl):
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, size=DEFAULT_SIZE, spacing=-2, 
                 style=0, maxlen=0, validator=wx.DefaultValidator, 
                 name=wx.ControlNameStr):
        KFloatCtrl.__init__(self, parent, id, label, orientation, pos, size, 
                            spacing, style, sign='€',sign_pos=FS_BEFORE, maxlen=maxlen,
                             validator=validator, name=name)

class KPercentoCtrl(KFloatCtrl):
    def __init__(self,parent, id=-1, label='', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, size=DEFAULT_SIZE, spacing=-2, 
                 style=0, maxlen=0, validator=wx.DefaultValidator, 
                 name=wx.ControlNameStr):
        KFloatCtrl.__init__(self, parent, id, label, orientation, pos, size, 
                            spacing, style, sign='%',sign_pos=FS_AFTER, maxlen=maxlen,
                             validator=validator, name=name)
    

#===============================================================================
# _KSpinCtrl
#===============================================================================
class _KSpinCtrl(wx.PyControl):
    def __init__(self,parent, id=-1, pos=wx.DefaultPosition, size=DEFAULT_SIZE, style=0, 
                 name='_KSpinCtrlBase'):
        wx.PyControl.__init__(self,parent,id,pos,style=wx.NO_BORDER)
        self._text=wx.TextCtrl(self,size=_init_size(size))
        self._spin=wx.SpinButton(self,size=(-1,self._text.GetSize().height),
                                 style=wx.SP_VERTICAL)
        self._spin.SetRange(0,10000)
        self._spin.SetValue(1)        
        self.Bind(wx.EVT_SPIN, self._spin_handler, self._spin)
        self._text.Bind(wx.EVT_CHAR,self._char_handler)
        self._text.Bind(wx.EVT_TEXT,self._text_handler)        
        self._layout()
    
    def _layout(self):        
        if 'win' in sys.platform:
            self._win_layout()
        else:
            self._default_layout()
        self.Layout()
    
    def _win_layout(self):
        self.SetSizer(wx.GridBagSizer())
        self.Sizer.Add(self._text,pos=(0,0))
        self.Sizer.Add(self._spin,pos=(0,1))
        self.SetInitialSize((self._text.GetSize().width + 
                            self._spin.GetSize().width + 
                            10, self._text.GetSize().height + 5))
    
    def _default_layout(self):
        w=self._text.GetSize().width
        ctrl_x,ctrl_y=self._text.GetPosition()
        self._spin.SetPosition((ctrl_x + w - self._spin.GetSize().width, ctrl_y))
        self.SetInitialSize((self._text.GetSize().width + 10,
                             self._text.GetSize().height + 5))
    
    def ChangeValue(self,val):
        self._text.ChangeValue(val)
    
    def _spin_handler(self,evt):
        self._text.ChangeValue(str(evt.GetPosition()))
    
    def _char_handler(self,evt):
        key=evt.GetKeyCode()        
        if (key==wx.WXK_TAB or key==wx.WXK_RETURN) and not evt.ShiftDown():
            self.Parent.Navigate()
            evt.Skip()
            return
        if (key==wx.WXK_TAB or key==wx.WXK_RETURN) and evt.ShiftDown():
            self.Parent.Navigate(wx.NavigationKeyEvent.IsBackward)
            evt.Skip()
            return
        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
            evt.Skip()
            return
        if chr(key) not in string.digits:#digits only
            evt.Skip(False)                          
            return       
        evt.Skip()
    
    def _text_handler(self,evt):
        val=evt.GetString()
        if not val:
            val=0
        self._spin.SetValue(int(val))
    
    def get_value(self):
        return self._text.GetValue()
    
    def set_value(self,val):
        self._text.ChangeValue(str(val))
        self._spin.SetValue(int(val))
    
    def SetFocus(self):
        self._text.SetFocus()


#===============================================================================
# _KSpinCtrlWin
#===============================================================================
class _KSpinCtrlWin(_KSpinCtrl):
    def __init__(self,parent, id=-1, pos=wx.DefaultPosition, size=DEFAULT_SIZE, style=0, 
                 name='KSpinCtrlWin'):
        _KSpinCtrl.__init__(self,parent,id,pos,size,style,name)
    
    def _layout(self):
        self.SetSizer(wx.GridBagSizer())
        self.Sizer.Add(self._text,pos=(0,0))
        self.Sizer.Add(self._spin,pos=(0,1))
        self.SetInitialSize((self._text.GetSize().width + 
                            self._spin.GetSize().width + 
                            10, self._text.GetSize().height + 5))
        self.Layout()
    
    
#===============================================================================
# _KSpinCtrl
#===============================================================================
class _KSpinCtrlDefault(_KSpinCtrl):
    def __init__(self,parent, id=-1, pos=wx.DefaultPosition, size=DEFAULT_SIZE, style=0, 
                 name='KSpinCtrl'):
        _KSpinCtrl.__init__(self,parent,id,pos,size,style,name)
    
    def _layout(self):
        w=self._text.GetSize().width
        ctrl_x,ctrl_y=self._text.GetPosition()
        self._spin.SetPosition((ctrl_x + w - self._spin.GetSize().width, ctrl_y))
#        self._spin=wx.SpinButton(self,pos=(ctrl_x + w - 15, ctrl_y),size=(24,h),
#                                 style=wx.SP_VERTICAL)
        
        #self.Sizer.Add(self._text,pos=(0,0))
        #self.Sizer.Add(self._spin,pos(0,1))
        self.SetInitialSize((self._text.GetSize().width + 10,
                             self._text.GetSize().height + 5))
        self.Layout()


#===============================================================================
# KQuantityCtrl 
#===============================================================================
class KQuantityCtrl(KControlBase):
    '''Usa _KSpinCtrlWin su Windows, _KSpinCtrl sulle altre piattaforme'''
    def __init__(self,parent, id=-1, label='Quantità', orientation=wx.HORIZONTAL,
                 pos=wx.DefaultPosition, size=DEFAULT_SIZE, spacing=-2, 
                 style=0, validator=wx.DefaultValidator, 
                 name=wx.ControlNameStr):
        KControlBase.__init__(self, parent, id, label, orientation, pos, spacing, name)
        self._set_control(_KSpinCtrl(self,size=size))        
        
        self.Layout()
    
    def get_value(self):
        return self._control.get_value()
    
    def set_value(self,val):
        self._control.set_value(str(val))
    
    value=property(get_value,set_value)

#if __name__=='__main__':
#    app=wx.PySimpleApp()
#    f=wx.Frame(None,-1)
#    p=mPickerCtrl(parent=f,id=-1)
#    sizer = wx.BoxSizer()
#    sizer.Add(p)
#    f.SetSizer(sizer)
#    f.Show()
#    app.MainLoop()
#    
